<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.dolibarr.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=ALSOFT</id>
	<title>Dolibarr ERP CRM Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.dolibarr.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=ALSOFT"/>
	<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php/Special:Contributions/ALSOFT"/>
	<updated>2026-10-27T07:03:54Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.17</generator>
	<entry>
		<id>https://wiki.dolibarr.org/index.php?title=Language_and_development_rules&amp;diff=49968</id>
		<title>Language and development rules</title>
		<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php?title=Language_and_development_rules&amp;diff=49968"/>
		<updated>2021-03-15T07:27:34Z</updated>

		<summary type="html">&lt;p&gt;ALSOFT: /* Index performance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- BEGIN origin interlang links --&amp;gt;&lt;br /&gt;
&amp;lt;!-- You can edit this section but do NOT remove these comments&lt;br /&gt;
     Links below will be automatically replicated on translated pages by PolyglotBot --&amp;gt;&lt;br /&gt;
[[de:Sprachen_und_Programmierregeln]]&lt;br /&gt;
[[fr:Langages_et_normes]]&lt;br /&gt;
[[es:Lenguaje_y_Normas_de_Desarrollo]]&lt;br /&gt;
[[zh:语言和开发规则]]&lt;br /&gt;
&amp;lt;!-- END interlang links --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{TemplateDocDevEn}}&lt;br /&gt;
&lt;br /&gt;
These are some rules on language, syntax and norm we use in the Dolibarr project:&lt;br /&gt;
&lt;br /&gt;
=Versions=&lt;br /&gt;
&lt;br /&gt;
*Dolibarr must work on:&lt;br /&gt;
&lt;br /&gt;
#All OS (Windows, Linux, MACOS...)&lt;br /&gt;
#PHP {{PHPMinVersion}} (Must work with no need of complementary PHP module, except module to PHP module to access database).&lt;br /&gt;
#MySQL {{MySqlMinVersion}}&lt;br /&gt;
&lt;br /&gt;
=Copyright Norms=&lt;br /&gt;
&lt;br /&gt;
*All PHP files must start with a header that looks like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/* Copyright (C) YYYY John Doe  &amp;lt;email@email.com&amp;gt;&lt;br /&gt;
 *&lt;br /&gt;
 * Licence information&lt;br /&gt;
 */&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
When you edit an existing file of project, you must add a Copyright line under others.&lt;br /&gt;
&lt;br /&gt;
=PHP Norms=&lt;br /&gt;
==PHP==&lt;br /&gt;
&lt;br /&gt;
*Dolibarr is written with PHP and supports all versions of PHP higher than {{PHPMinVersion}}. All files must end with extension .php&lt;br /&gt;
&lt;br /&gt;
*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..&lt;br /&gt;
&lt;br /&gt;
*Other operators ($HTTP_SERVER_GET, ...) are now deprecated in PHP, so they must not be used. Code must work if option &#039;&#039;&#039;register_long_arrays&#039;&#039;&#039; is set to off. Moreover, the code must work when PHP option &#039;&#039;&#039;register_globals&#039;&#039;&#039; is off (recommended by PHP). It must also work  if the option &#039;&#039;&#039;register_globals&#039;&#039;&#039; is on (by default on a lot of installations).&lt;br /&gt;
&lt;br /&gt;
*Do not use &#039;&#039;&#039;&amp;lt;s&amp;gt;PHP_SELF&amp;lt;/s&amp;gt;&#039;&#039;&#039;. Use instead &#039;&#039;&#039;$_SERVER[&amp;quot;PHP_SELF&amp;quot;]&#039;&#039;&#039;. Also, Dolibarr framework sanitizes content of $_SERVER[&amp;quot;PHP_SELF&amp;quot;] variable (into main.inc.php file, before any business code).&lt;br /&gt;
&lt;br /&gt;
*When several variables must be initialized with the same value, you must use individual declarations (separated by ;)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$var1 = 1;&lt;br /&gt;
$var2 = 1;&lt;br /&gt;
$var3 = 1;&lt;br /&gt;
&amp;lt;/sousyntaxhighlightrce&amp;gt;&lt;br /&gt;
instead of&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$var1 = $var2 = $var3 = 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which is slower.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Strings====&lt;br /&gt;
&lt;br /&gt;
*Strings must be have variables outside of the quote.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
print &amp;quot;My text show my &amp;quot;.$variable.&amp;quot; !\n&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Comments====&lt;br /&gt;
&lt;br /&gt;
*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&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
/* Bloc of comment&lt;br /&gt;
 *&lt;br /&gt;
 * End of bloc&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
$monobjet = new MonObjet($db);&lt;br /&gt;
$result=$monobjet-&amp;gt;fetch($idobject);&lt;br /&gt;
&lt;br /&gt;
for ($i = 1 , $i &amp;lt; 2 ; $i++) {&lt;br /&gt;
    // comment on one line&lt;br /&gt;
    print $i;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function myFunction($param1, $param2)&lt;br /&gt;
{&lt;br /&gt;
    // code&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Functions must return a value equal or higher than 0 if successful and strictly lower than 0 if error.&lt;br /&gt;
&lt;br /&gt;
*No dead code (code never used) into Dolibarr core code (code used by external modules only must be included within the external modules).&lt;br /&gt;
&lt;br /&gt;
*Use &amp;quot;include_once&amp;quot; for anything with functions or class definitions in it (like *.class.php and *.lib.php files), use &amp;quot;include&amp;quot; for template-style php with files containing common part of HTML and PHP code (like *.inc.php and *.tpl.php files).&lt;br /&gt;
&lt;br /&gt;
*Coding style to use is the &#039;&#039;&#039;PSR-12&#039;&#039;&#039; (https://www.php-fig.org/psr/psr-12/). Only rules tagged &amp;quot;MUST&amp;quot; are currently required. So note however the exceptions:&lt;br /&gt;
**Length of line: PSR-12 mention we can&#039;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 &#039;&#039;&#039;1000&#039;&#039;&#039; characters (having line larger than this may return errors on Continuous Integration tests).&lt;br /&gt;
**Tabs are allowed: The other exception is that we don&#039;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 &amp;quot;Keep spaces/tabs as it is&amp;quot;, however, you can activate the option &amp;quot;Remove spaces at end of lines&amp;quot;.&lt;br /&gt;
**We allow elements of an array on same line and we do not always add a new line at end of each element.&lt;br /&gt;
**Note 1: The following rule are very important to follow:&lt;br /&gt;
***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.&lt;br /&gt;
***Smart tags PHP are not used. PHP code section must start with &#039;&#039;&#039;&amp;lt;?php&#039;&#039;&#039;&lt;br /&gt;
**Note 2: You can use the file &#039;&#039;&#039;dev/setup/codesniffer/ruleset.xml&#039;&#039;&#039; as rule file to control coding style with PHPCodeSniffer.&lt;br /&gt;
**Note 3: You can use the file &#039;&#039;&#039;dev/setup/eclipse/PSR-12 [built-in].xml&#039;&#039;&#039; as rule file to setup Eclipse syntax formater.&lt;br /&gt;
**Note 4: You may note that current code is not yet compliant with the PSR-12. The reason is that we must &amp;quot;now&amp;quot; follow the &amp;quot;MUST&amp;quot; rules of PSR-12, but it wasn&#039;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.&lt;br /&gt;
&lt;br /&gt;
==Classes and properties structures==&lt;br /&gt;
&lt;br /&gt;
Some properties of classes are found in different classes. To avoid having different names, we will use the following PHP properties names:&lt;br /&gt;
&lt;br /&gt;
{{TemplatePHPFields}}&lt;br /&gt;
&lt;br /&gt;
=SQL rules=&lt;br /&gt;
&lt;br /&gt;
==DDL file format==&lt;br /&gt;
Files containing definition of the database structure (DDL files) must be &#039;&#039;&#039;2 per table&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
*The first file defines the table and its fields. The file name contains the table name, e.g. like this: &amp;lt;tt&amp;gt;llx_&#039;&#039;mytable&#039;&#039;.sql&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A comment will be added for each field to explain its usage.&lt;br /&gt;
&lt;br /&gt;
*The second file defines all foreign keys, performance indexes or other constraints and the file name will be like: &amp;lt;tt&amp;gt;llx_&#039;&#039;mytable&#039;&#039;.key.sql&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These files must be stored in the directory &#039;&#039;&#039;install/mysql/tables&#039;&#039;&#039; for all standard files or &#039;&#039;&#039;mymodule/tables&#039;&#039;&#039; for tables provided by an external module.&lt;br /&gt;
&lt;br /&gt;
Example: &#039;&#039;&#039;file for creating the table llx_mytable will be llx_mytable.sql&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- ===========================================================================&lt;br /&gt;
-- Copyright (C) 2013 Author &amp;lt;email@author.com&amp;gt;&lt;br /&gt;
-- &lt;br /&gt;
-- This program is free software; you can redistribute it and/or modify&lt;br /&gt;
-- it under the terms of the GNU General Public License as published by&lt;br /&gt;
-- the Free Software Foundation; either version 3 of the License, or&lt;br /&gt;
-- (at your option) any later version.&lt;br /&gt;
--&lt;br /&gt;
-- This program is distributed in the hope that it will be useful,&lt;br /&gt;
-- but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
-- GNU General Public License for more details.&lt;br /&gt;
--&lt;br /&gt;
-- You should have received a copy of the GNU General Public License&lt;br /&gt;
-- along with this program. If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
-- ===========================================================================&lt;br /&gt;
&lt;br /&gt;
create table llx_mytable&lt;br /&gt;
(&lt;br /&gt;
  rowid       integer NOT NULL AUTO_INCREMENT PRIMARY KEY,&lt;br /&gt;
  ref	      varchar(30)       NOT NULL,		-- object reference number&lt;br /&gt;
  entity      integer DEFAULT 1 NOT NULL,	        -- multi company id&lt;br /&gt;
  ref_ext     varchar(255),-- reference into an external system (not used by dolibarr)&lt;br /&gt;
  field_one   integer,&lt;br /&gt;
  field_two   integer NOT NULL,&lt;br /&gt;
  fk_field    integer,&lt;br /&gt;
  field_date  datetime,&lt;br /&gt;
  datec       timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,,   -- creation datetime&lt;br /&gt;
  tms         timestamp,    -- update time stamp&lt;br /&gt;
  fk_user_author integer NOT NULL,                     -- Author, foreign key of llx_user&lt;br /&gt;
  fk_user_mod    integer NOT NULL,                      -- Last updater, foreign key of llx_user&lt;br /&gt;
  import_key	varchar(14)                -- Use by import process&lt;br /&gt;
)type=innodb;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: &#039;&#039;&#039;file for creating keys/indexes for the table llx_mytable will be llx_mytable.key.sql&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- ===========================================================================&lt;br /&gt;
-- Copyright (C) 2013 Author &amp;lt;email@author.com&amp;gt;&lt;br /&gt;
-- &lt;br /&gt;
-- This program is free software; you can redistribute it and/or modify&lt;br /&gt;
-- it under the terms of the GNU General Public License as published by&lt;br /&gt;
-- the Free Software Foundation; either version 3 of the License, or&lt;br /&gt;
-- (at your option) any later version.&lt;br /&gt;
--&lt;br /&gt;
-- This program is distributed in the hope that it will be useful,&lt;br /&gt;
-- but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
-- GNU General Public License for more details.&lt;br /&gt;
--&lt;br /&gt;
-- You should have received a copy of the GNU General Public License&lt;br /&gt;
-- along with this program. If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
-- ===========================================================================&lt;br /&gt;
&lt;br /&gt;
ALTER TABLE llx_mytable ADD UNIQUE uk_mytable_field (field_one, field_two);&lt;br /&gt;
&lt;br /&gt;
ALTER TABLE llx_mytable ADD CONSTRAINT fk_mytable_fk_field FOREIGN KEY (fk_field) REFERENCES llx_matablepere (rowid);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Table and fields structures==&lt;br /&gt;
&lt;br /&gt;
*Structure of tables.&lt;br /&gt;
&lt;br /&gt;
When you create a new table, it is recommended to use the same conventions as other Dolibarr tables. This means the following fields:&lt;br /&gt;
 - rowid INTEGER AUTO_INCREMENT PRIMARY KEY    that is technical id of record&lt;br /&gt;
 - entity INTEGER default 1                    that is id for the multicompany feature&lt;br /&gt;
 - date_creation   datetime                    that is the creation date&lt;br /&gt;
 - tms             timestamp                   that will contain date of last modification (the database manages this field automatically, no need to manage it by the code, just create the field)&lt;br /&gt;
 - date_valid      datetime                    that is the validation date (if applicable)&lt;br /&gt;
 - import_key      varchar(32)                 that will contains the import code YYYYMMDDHHMMSS if you make mass import.&lt;br /&gt;
 - status          smallint                    to store a status&lt;br /&gt;
Eventually&lt;br /&gt;
 - fk_user_creat or fk_user_author integer that is the id of user making creation&lt;br /&gt;
 - fk_user_modif integer that is the id of user making change&lt;br /&gt;
 - fk_user_valid integer that is the id of user validating record (if applicable)&lt;br /&gt;
 - fk_soc integer that is the ID of the Third party (if applicable)&lt;br /&gt;
&lt;br /&gt;
Note field:&lt;br /&gt;
 - note_private text for private comment of the object&lt;br /&gt;
 - note_pubic text for public comment of the object&lt;br /&gt;
or &lt;br /&gt;
 - note text if there is no need to have private and public&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Type of fields:&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 - integer for a primary key, an integer or any of foreign key (bigint may also be accepted for very large tables)&lt;br /&gt;
 - smallint for a small number (like for a status) or a boolean&lt;br /&gt;
 - double(24,8) for any amount&lt;br /&gt;
 - double(6,3) for any vat rate&lt;br /&gt;
 - real for a quantity&lt;br /&gt;
 - varchar for a string (also if length is 1, the type char is more and more deprecated)&lt;br /&gt;
 - timestamp for a field date+time that is automatically updated&lt;br /&gt;
 - datetime for a field date+time&lt;br /&gt;
 - date for a field date&lt;br /&gt;
 - text or medium text for large fields (no index allowed on such fields)&lt;br /&gt;
&lt;br /&gt;
All business rules must be on same place, into PHP code, not into client, neither into database, that&#039;s why type enum is also not allowed.&lt;br /&gt;
Other type are not allowed for compatibility reasons. &lt;br /&gt;
&lt;br /&gt;
*All tables has a prefix to avoid name conflicts with other projects. In current version this prefix is fixed ans can&#039;t be modified. Its value is &amp;lt;tt&amp;gt;llx_&amp;lt;/tt&amp;gt;. In a future version this value should be modified during installation process.&lt;br /&gt;
&lt;br /&gt;
==Primary keys==&lt;br /&gt;
The primary key of a table must be called &amp;lt;tt&amp;gt;rowid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Some old tables does not use this rule and use a primary key called &amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt; (ie [[Table llx_c_actioncomm]]), but the reason is history and this should not happen anymore.&lt;br /&gt;
&lt;br /&gt;
==Foreign keys==&lt;br /&gt;
Name of a foreign key must start with the prefix &amp;lt;tt&amp;gt;fk_&amp;lt;/tt&amp;gt; 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).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&#039;&#039;fk_facture_fourn_fk_soc&#039;&#039;  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)&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==Alternative keys==&lt;br /&gt;
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 &amp;lt;tt&amp;gt;uk_&amp;lt;/tt&amp;gt; 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).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&#039;&#039;uk_societe_code_client&#039;&#039; is a unique key on table llx_societe on field code_client.&lt;br /&gt;
&lt;br /&gt;
==Index performance==&lt;br /&gt;
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 &amp;lt;tt&amp;gt;idx_&amp;lt;/tt&amp;gt; then the table name and then the field name.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&#039;&#039;idx_societe_user_creat&#039;&#039; is a performance index on table llx_societe for field user_creat&lt;br /&gt;
&lt;br /&gt;
==SQL Coding rules==&lt;br /&gt;
&lt;br /&gt;
*Alias usage/Fields naming&lt;br /&gt;
&lt;br /&gt;
When doing select, we can use alias to simplify writing/reading of requests:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
select chp1, chpxxx2 as chp2 from table2 as t1, table2 as t2 where t1.chpx = t2.chpy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
However, we must not used alias for update request as they are not compatible with Mysql 3.1.&lt;br /&gt;
&lt;br /&gt;
*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:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT field_a, field_b, field_c FROM table_1 WHERE field_d = &#039;$id&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*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&#039;s PHP that has the good vision. There is really a wrong value into database. By removing quotes on numbers, no problem occurs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
Good:     INSERT INTO table_1 (field_txt, field_num) VALUES (&#039;txt&#039;, 412.62)&lt;br /&gt;
Bad:      INSERT INTO table_1 (field_txt, field_num) VALUES (&#039;txt&#039;, &#039;412.62&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;real&amp;quot; numbers, so numbers must be, as soon as they are affected, cleaned with function price2num with second parameter defined to :&lt;br /&gt;
&#039;MU&#039; (for unit prices), &#039;MT&#039; (for total prices) or &#039;MS&#039; (otherwise) depending on usage of number. (see function documentation)&lt;br /&gt;
&lt;br /&gt;
*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.&lt;br /&gt;
&lt;br /&gt;
For example, don&#039;t do:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$sql=&amp;quot;SELECT rowid FROM table where datefield = NOW()&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
but do:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$sql=&amp;quot;SELECT rowid FROM table where datefield = &#039;&amp;quot;.$this-&amp;gt;db-&amp;gt;idate(dol_now()).&amp;quot;&#039;&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, don&#039;t do:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$sql=&amp;quot;SELECT rowid FROM table where DATEDIFF(table.datefield, NOW()) &amp;gt; 7&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
but do:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$sql=&amp;quot;SELECT rowid FROM table where datefield &amp;lt; &#039;&amp;quot;.$this-&amp;gt;db-&amp;gt;idate(dol_now() - (7 * 24 * 3600)).&amp;quot;&#039;&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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&#039;t use the index on field, resulting on very bad performance compared to solution without the datediff.&lt;br /&gt;
&lt;br /&gt;
*Use $db-&amp;gt;ifsql for SQL IF&lt;br /&gt;
&lt;br /&gt;
Do not include the IF into your forged SQL request. But use instead $db-&amp;gt;ifsql() method to you will make a SQL IF that is compatible with all SQL databases.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using Database triggers==&lt;br /&gt;
Using Database triggers is not allowed into the code of Dolibarr, so you should have no troubles with Database triggers. &lt;br /&gt;
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 &amp;quot;business rules&amp;quot; of your application into the database where most other rules are managed by the code itself creating conflict or code that can&#039;t be debugged with a step by step debugger, ...&lt;br /&gt;
There is tons of reason why we do not recommand to use database triggers in your own development. &lt;br /&gt;
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&#039;t work for more than 50% of users.&lt;br /&gt;
&lt;br /&gt;
==MySQL-MariaDB specificity==&lt;br /&gt;
&lt;br /&gt;
*Tables must be declared with format InnoDB.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
*Dolibarr MUST work even if MySQL option &#039;&#039;&#039;strict&#039;&#039;&#039; is active.&lt;br /&gt;
&lt;br /&gt;
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)&lt;br /&gt;
{{MySqlStrictMode}}&lt;br /&gt;
&lt;br /&gt;
==PostgreSQL specificities==&lt;br /&gt;
Only MySQL files must be maintained.&lt;br /&gt;
Those files are converted &amp;quot;on the fly&amp;quot; by the database Dolibarr driver.&lt;br /&gt;
&lt;br /&gt;
There is an exception for the SQL &amp;quot;UPDATE FROM&amp;quot;: &lt;br /&gt;
&lt;br /&gt;
MySQL Syntax:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE table_taget as target, table_source as source SET fieldtarget=source.fieldsource&lt;br /&gt;
WHERE source.rowid=target.rowid;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PgSQL Syntax:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE table_taget as target SET fieldtarget=source.fieldsource&lt;br /&gt;
FROM table_source as source WHERE source.rowid=target.rowid;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is no native SQL requests &amp;quot;UPDATE FROM&amp;quot; in all Dolibarr core. But if you use one in your own code of your module, you should do :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
if ($this-&amp;gt;db-&amp;gt;type==&#039;pgsql&#039;) {&lt;br /&gt;
$sql=&amp;quot;UPDATE table_taget as target SET fieldtarget=source.fieldsource&lt;br /&gt;
FROM table_source as source WHERE source.rowid=target.rowid&amp;quot;;&lt;br /&gt;
} else {&lt;br /&gt;
$sql= &amp;quot;UPDATE table_taget as target, table_source as source SET fieldtarget=source.fieldsource&lt;br /&gt;
WHERE source.rowid=target.rowid&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=HTML norms=&lt;br /&gt;
==Syntax rules==&lt;br /&gt;
&lt;br /&gt;
*HTML used must be HTML compliant and not XHTML. All attributes of HTML tags must be in lower case and quoted with &amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*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().&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
print &#039;&amp;lt;a href=&amp;quot;&#039;.dol_buildpath(&#039;/mydir/mypage.php&#039;).&#039;&amp;quot;&amp;gt;&#039;.img_picto(&#039;Texte alt&#039;,&#039;namepictopng&#039;,&#039;&#039;).&#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*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=&amp;quot;20px&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
*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 &amp;quot;$conf-&amp;gt;use_javascript_ajax&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
if ($conf-&amp;gt;use_javascript_ajax) {&lt;br /&gt;
...  // php code generating javascript here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Popup windows must not be used, except for tooltips (and must have a condition as explained before).&lt;br /&gt;
&lt;br /&gt;
*External scripts must be written in Perl if they can&#039;t be written in PHP. Usage of another language is not forbidden but must be argued before in the development mailing-list.&lt;br /&gt;
&lt;br /&gt;
==External templating framework ?==&lt;br /&gt;
There is ton of frameworks to provide a templating language of an HTML page. The best and faster is just called &amp;quot;PHP&amp;quot;, and because Dolibarr already depends on PHP, there is no need to introduce a dependency on a third language.&lt;br /&gt;
&lt;br /&gt;
All templating frameworks are just preprocessor, BEFORE PHP. It can&#039;t be faster than PHP alone. When we say &amp;quot;speed is increased because templating framework use a cache&amp;quot;, you must read in fact &amp;quot;the overtime spent by the framework is reduced by cache, not the speed of processing PHP file&amp;quot;. We should say &amp;quot;any templating framework has an overload over PHP, the cache of the templating framework just reduces the slowing effect of using this framework&amp;quot;, but not &amp;quot;the speed is increased, it is always decreased compared to pure PHP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Above all, having a templating system is completely possible by doing a &amp;quot;&#039;&#039;&#039;.tpl.php&#039;&#039;&#039;&amp;quot; file that dos not contains any logic code, but only HTML and &amp;quot;echo&amp;quot;. 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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=Dolibarr norms and code skeleton=&lt;br /&gt;
&lt;br /&gt;
==Skeleton code==&lt;br /&gt;
To standardize the code, and to speed up the development of new components in Dolibarr, you&#039;ll find skeletons of files fully prepared in the directory &#039;&#039;&#039;htdocs/modulebuilder/templates/&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
*1 file that serves as an example of the module description: &#039;&#039;&#039;myModule.class.php&#039;&#039;&#039;&lt;br /&gt;
*1 file that serves as an example of code for creating a new class: &#039;&#039;&#039;skeleton_class.class.php&#039;&#039;&#039;&lt;br /&gt;
*1 file that serves as an example of code for creating a new page: &#039;&#039;&#039;skeleton_page.php&#039;&#039;&#039;&lt;br /&gt;
*1 file that serves as an example of code for creating a script for executing command lines: &#039;&#039;&#039;skeleton_script.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
Use it as an example.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==Dates and Timezones==&lt;br /&gt;
Dolibarr is an application that is multi-user and multi-location. It&#039;s therefore necessary to store dates in the right format. To avoid problems with conversions, the following rules should be applied:&lt;br /&gt;
&lt;br /&gt;
*A date into memory must always be stored with Timestamp GMT format.&lt;br /&gt;
*A date stored into database, is the GMT Timestamp of date submitted into the request usng the &amp;lt;b&amp;gt;PHP server&amp;lt;/b&amp;gt; timezone. This does not apply to date update automatically by database (fields &#039;&#039;&#039;tms&#039;&#039;&#039; into database).&lt;br /&gt;
&lt;br /&gt;
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 &#039;19700101030000&#039; (PHP convert into its TZ hour and database will unconvert it using its timezone too that is same than PHP).&lt;br /&gt;
&lt;br /&gt;
All select methods should translate date fields, that are with format TZ of database (&#039;19700101030000&#039;), into a timestamp field by calling the method db-&amp;gt;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-&amp;gt;idate (you may find examples into skeleton).&lt;br /&gt;
&lt;br /&gt;
*Dates that are updated automatically (field &#039;&#039;&#039;tms&#039;&#039;&#039; into database) contains a GMT Timestamp GMT of date when change is done. The select will also use the db-&amp;gt;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.&lt;br /&gt;
&lt;br /&gt;
*Manipulation date with PHP must be done using the Dolibarr date functions: &#039;&#039;&#039;dol_now(), dol_mktime(), dol_stringtotime(), dol_getdate(), dol_time_plus_duree()&#039;&#039;&#039;. You may also find other functions available into file &#039;&#039;&#039;date.lib.php&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==UTF8/ISO encoding==&lt;br /&gt;
Dolibarr stores data in the following way:&lt;br /&gt;
&lt;br /&gt;
*In database, data is stored in UTF8 or ISO. It depends on the database&#039;s pagecode therefore these options are set at creation time. In any case, Dolibarr&#039;s database driver (in lib/database) deals with it to convert from/to UTF8 at insertion and readout.&lt;br /&gt;
*Memory data is stored in UTF8 (PHP object instances).&lt;br /&gt;
*Web pages are returned and rendered into UTF8&lt;br /&gt;
&lt;br /&gt;
==Float numbers, amount and calculation==&lt;br /&gt;
With PHP, like other languages (Java for exemple), non integer data (float, real, double) are not reliable for calculation.&lt;br /&gt;
Try to make for example &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
print 239.2 - 229.3 - 9.9;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You wont get zero but a very small decimal number. If you get zero her, you should be able to find other examples that don&#039;t work.&lt;br /&gt;
Problem of float is general, so a variable that is a result of a calculation using decimal numbers must ALWAYS be cleaned using the function &#039;&#039;&#039;price2num()&#039;&#039;&#039; with the econd parameter to: &#039;MU&#039;, &#039;MT&#039; or &#039;MS&#039; depending on need (see description of function).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
print price2num(239.2 - 229.3 - 9.9, &#039;MT&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If data manipulated is not an amount, then using MU, MT, MS has no sense, and you must use the function &#039;&#039;&#039;round()&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Creation of tables==&lt;br /&gt;
Do not create tables, on the fly, during execution by a standard user, we mean, during current usage of software.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==Comparing version==&lt;br /&gt;
If your code need to make different things depending on Dolibarr version, you can use the following tip to detect and compare versions&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$version=preg_split(&#039;/[\.-]/&#039;,DOL_VERSION);&lt;br /&gt;
if (versioncompare($version,array(5,0,-4)) &amp;gt;= 0) { //mycode for 5.0 only; }	// For dolibarr 5.0.* (the -4 means we include also alpha, beta, rc and rcX)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But this solution need to include the function versioncompare. An alternative solution to test version is to do:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
if ((float) DOL_VERSION &amp;gt;= 5.0) { //mycode for 5.0 only; }	// For dolibarr 5.0.*&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Logs==&lt;br /&gt;
Add logs to your code using function&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
dol_syslog($yourmessage, LOG_INFO|LOG_DEBUG|LOG_WARNING|LOG_ERR);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Working directory==&lt;br /&gt;
If you need to create a working directory, into your code, refer to it with &lt;br /&gt;
&#039;&#039;&#039;DOL_DATA_ROOT.&#039;/mymodule&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The directory can be created into your code by the following function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$mymoduledir=DOL_DATA_ROOT.&#039;/mymodule&#039;;&lt;br /&gt;
dol_mkdir($mymoduledir);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need a directory to store temporary data, this directory must be &#039;&#039;&#039;DOL_DATA_ROOT.&#039;/mymodule/temp&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Design patterns and Object programming=&lt;br /&gt;
&lt;br /&gt;
==Creation design patterns (GoF)==&lt;br /&gt;
Design patterns defined by the Gang Of Four (see wikipédia on [[w:Design patterns|Design patterns]]).&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==Structure design patterns (GoF)==&lt;br /&gt;
Design patterns defined by the Gang Of Four (see wikipédia on [[w:Design patterns|Design patterns]]). &lt;br /&gt;
No usage of such patterns is required.&lt;br /&gt;
&lt;br /&gt;
==Behavior design patterns (GoF)==&lt;br /&gt;
Design patterns defined by the Gang Of Four (see wikipédia on [[w:Design patterns|Design patterns]]). &lt;br /&gt;
No usage of such patterns is required.&lt;br /&gt;
&lt;br /&gt;
==Design patterns of enterprise (Martin Fowler)==&lt;br /&gt;
&lt;br /&gt;
===Patterns of code organization===&lt;br /&gt;
[[w:Martin Fowler|Martin Fowler]] has identified 3 ways to organize code:&lt;br /&gt;
&lt;br /&gt;
*The &#039;&#039;&#039;Transaction Script&#039;&#039;&#039; (The source code is linear for each user action).&lt;br /&gt;
&lt;br /&gt;
This is the old school used by all procedural languages.&lt;br /&gt;
Inconvenient: Redundancy of code. Need to know the physical model of data to develop.&lt;br /&gt;
&lt;br /&gt;
*The &#039;&#039;&#039;Domain Model&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This notion is available with object languages. It is business process (to identify before) that are used for objects classes.&lt;br /&gt;
Inconvenient: Model very complex to maintain.&lt;br /&gt;
&lt;br /&gt;
*The &#039;&#039;&#039;Table Module&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This is a mix between 2 previous where we have only one unique class for each table of database.&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; As shown in code skeletons (see previous chapter), Dolibarr uses concept of &#039;&#039;&#039;Table Module&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Communication between business logic - data (ORM)===&lt;br /&gt;
&lt;br /&gt;
There are 3 ways to make links:&lt;br /&gt;
&lt;br /&gt;
*The &#039;&#039;&#039;Table And Row Data Gateway&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Example: This mode is used by some ORM Frameworks, like &#039;&#039;&#039;iBatis&#039;&#039;&#039; (http://ibatis.apache.org/).&lt;br /&gt;
&lt;br /&gt;
*The &#039;&#039;&#039;Active Record&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Example: This mode is used for Dolibarr development and most PHP software that includes their own framework and best practices.&lt;br /&gt;
&lt;br /&gt;
*The &#039;&#039;&#039;Data Mapper&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
More &amp;quot;purist&amp;quot; on paper (closer of business), this method also has the disadvantage of being more complex in practice.&lt;br /&gt;
&lt;br /&gt;
Example: This is the choice if you use the ORM Framework &#039;&#039;&#039;Propel&#039;&#039;&#039; (http://propel.phpdb.org/trac/). We find this model in heavier applications, based on this ORM among others.&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; For Dolibarr development, it is recommended to use the connection mode &#039;&#039;&#039;Active Record&#039;&#039;&#039;, 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).&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
==Design pattern for Graphic interfaces (MVC)==&lt;br /&gt;
There are several design patterns for user interfaces (MVC, MVP, MVVM).&lt;br /&gt;
Many confuse this design pattern with that of using a template framework. It&#039;s unrelated. A template framework (see previous point) is only linked to the &amp;quot;V&amp;quot; part of these models.&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; Dolibarr uses the &#039;&#039;&#039;MVC&#039;&#039;&#039; Design Pattern. Part M is materialized by a DAO class containing the CRUD (Create-Read-Update-Delete) methods for accessing the table.&lt;br /&gt;
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&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Actions&lt;br /&gt;
 * /&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is followed by the part of code V (Vue), well separated from the C by the tag&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * View&lt;br /&gt;
 * /&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This mode of separation has had a neutral effect on new developments but has made it possible to reduce the time required for maintenance and fixing bugs so significantly that it is not envisaged to switch to another type of separation (yes the findings made in real life are not always those expected by school theory). The important thing remains that there is always a separation between C and V, no matter how this separation is materialized, as long as it is (Reminder: Do not confuse the notion of separation of C and V with the notion of separation of the code to feed the data of a View and of the code to format the View, this a principle of separation relating to the Design Pattern of Vue, see next point).&lt;br /&gt;
&lt;br /&gt;
==Design pattern for Views - Presentation==&lt;br /&gt;
There are frameworks that specialize in Vue Design Pattern, the part of formatting the screen seen by the user.&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
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&#039; code.&lt;br /&gt;
&lt;br /&gt;
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.&lt;/div&gt;</summary>
		<author><name>ALSOFT</name></author>
	</entry>
	<entry>
		<id>https://wiki.dolibarr.org/index.php?title=Module_development&amp;diff=49944</id>
		<title>Module development</title>
		<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php?title=Module_development&amp;diff=49944"/>
		<updated>2021-03-10T12:21:22Z</updated>

		<summary type="html">&lt;p&gt;ALSOFT: /* Add your own permissions (optional) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- BEGIN origin interlang links --&amp;gt;&lt;br /&gt;
&amp;lt;!-- You can edit this section but do NOT remove these comments&lt;br /&gt;
     Links below will be automatically replicated on translated pages by PolyglotBot --&amp;gt;&lt;br /&gt;
[[fr:Développement_module]]&lt;br /&gt;
[[es:Desarrollo_de_un_módulo]]&lt;br /&gt;
[[de:Modul_Entwicklung]]&lt;br /&gt;
[[zh:模块开发]]&lt;br /&gt;
&amp;lt;!-- END interlang links --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
{{TemplateDocDevEn}}&lt;br /&gt;
&lt;br /&gt;
To create a new module/addon for Dolibarr, there is several steps. This tutorial will describe you each of them to build a module to extend Dolibarr features, like one or several of the following :&lt;br /&gt;
&lt;br /&gt;
*Add new tables in database&lt;br /&gt;
*Add your own menu entries&lt;br /&gt;
*Add new screens to edit new tables&lt;br /&gt;
*Add or remove tabs on object view (invoice, product, order, event, ...)&lt;br /&gt;
*Add predefined exports for the internal export tool&lt;br /&gt;
*Add new information boxes in the home page&lt;br /&gt;
*Add new substitutions variables&lt;br /&gt;
*Define new permissions&lt;br /&gt;
*Execute code automatically triggered by a particular Dolibarr action&lt;br /&gt;
*Insert your code inside Dolibarr hooks positions&lt;br /&gt;
*Add your numbering module&lt;br /&gt;
*Add a new document template&lt;br /&gt;
*Add a new skin&lt;br /&gt;
&lt;br /&gt;
etc...&lt;br /&gt;
&lt;br /&gt;
Following chapters presents how to do all of this manually with an easy way.&lt;br /&gt;
&lt;br /&gt;
=Module creation with the module builder=&lt;br /&gt;
From Dolibarr 9.0 it is possible to create the main pages of your module with the Module Builder. To activate it, go into the list of module and enable the module &amp;quot;Module Builder&amp;quot;, then click on the &amp;quot;bug&amp;quot; image in the top right of screen.&lt;br /&gt;
&lt;br /&gt;
=Example of Template External Module=&lt;br /&gt;
A good model to start development of external module can be found here : [https://github.com/Dolibarr/dolibarr/tree/develop/htdocs/modulebuilder/template GitHub Dolibarr Module Modèle]&lt;br /&gt;
&lt;br /&gt;
=Create your module=&lt;br /&gt;
==Create a Module descriptor for your Module (required)==&lt;br /&gt;
&#039;&#039;&#039;When it is required&#039;&#039;&#039;: Required as soon as an addon is developed, whatever its goal is (except for adding a skin).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since Dolibarr 9.0, you should use the ModuleBuilder module provided as a standard module to generate the module descriptor&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Create your module descriptor===&lt;br /&gt;
The first step is to create a file descriptor for the module. &lt;br /&gt;
&lt;br /&gt;
*Create directory &#039;&#039;&#039;/htdocs/&#039;&#039;mymodule&#039;&#039;/core/modules&#039;&#039;&#039;. Then copy the file modMyModule.class.php from the directory dev/skeletons into this directory &#039;&#039;&#039;htdocs/&#039;&#039;mymodule&#039;&#039;/core/modules&#039;&#039;&#039;. Change the name of the file modMyModule.class.php to the name corresponding to the purpose of your module. Name of the file must start with initial &#039;mod&#039; and end with .class.php (for example if you want to give the name &#039;NewName&#039; to this file, then the name should be &#039;modNewName.class.php&#039;).&lt;br /&gt;
&lt;br /&gt;
Next modify the contents of this file as follows:&lt;br /&gt;
&lt;br /&gt;
*Replace all &amp;quot;modMyModule&amp;quot; with a value which corresponds to the purpose of your module. This value must always start with &#039;mod&#039; and contain only alpha characters (again, if the name given to the file was &#039;NewName&#039;, then replace all &amp;quot;modMyModule&amp;quot; with &amp;quot;modNewName&amp;quot;).&lt;br /&gt;
*Change the number in: $this-&amp;gt;numero = 100000 by a number that designates your module id. To avoid conflicts with other modules, you can consult the page that lists already reserved id numbers: [[List of modules id|List of modules id]].&lt;br /&gt;
*Modify any other variables defined in the constructor (see comment in the code skeleton for their meaning).&lt;br /&gt;
&lt;br /&gt;
Your file descriptor for your module is ready. See the next step to activate it.&lt;br /&gt;
&lt;br /&gt;
===Test your descriptor===&lt;br /&gt;
&lt;br /&gt;
Launch Dolibarr and go to page &#039;&#039;&#039;Setup-&amp;gt;module&#039;&#039;&#039;? &lt;br /&gt;
If you set the property version in the module description you should see a new line with your new module and the possibility to activate it or not. If you set the property version to &amp;quot;develop&amp;quot; or &amp;quot;experiental&amp;quot;, to see your module, you must first go into &#039;&#039;&#039;Setup-Others&#039;&#039;&#039; and set MAIN_FEATURES_LEVEL to 1 to see &amp;quot;experimental&amp;quot; modules or 2 to see &amp;quot;development&amp;quot; modules.&lt;br /&gt;
&lt;br /&gt;
==Tree of path for new module files (required)==&lt;br /&gt;
This is how your files must be organized when building a new module (the zip file must also match this rule).&lt;br /&gt;
Note: Only the second line is mandatory.&lt;br /&gt;
&lt;br /&gt;
{{TemplateModuleTreeSimple}}&lt;br /&gt;
&lt;br /&gt;
==Create your SQL tables and the PHP DAO class (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs to manage data of its own&lt;br /&gt;
&lt;br /&gt;
===Create your .sql file===&lt;br /&gt;
If your module is designed to manage data of its own, which are not available in the standard version of Dolibarr, it is necessary to define SQL tables to store the data.&lt;br /&gt;
&lt;br /&gt;
Scripts for creating tables and load data by your own module are saved into a subdirectory called &amp;quot;/mymodule/sql&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Then check into your descriptor file, into function &#039;&#039;&#039;init&#039;&#039;&#039; that the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;$this-&amp;gt;_load_tables(&#039;/mymodule/sql/&#039;);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
is not commented.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Rules to follow:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Add the files about creating tables commands on the principle of a file &#039;&#039;&#039;llx_matable.sql&#039;&#039;&#039; per table, with a possibly file &#039;&#039;&#039;llx_matable.key.sql&#039;&#039;&#039; (see existing files in &#039;&#039;&#039;install/mysql/tables&#039;&#039;&#039; for examples).&lt;br /&gt;
*The recommended type and name for SQL fields are defined into page [[Language_and_development_rules#Table_and_fields_structures]].&lt;br /&gt;
*To manage data, you must create a file called &#039;&#039;&#039;data.sql&#039;&#039;&#039; inside directory &#039;&#039;&#039;/mymodule/sql/&#039;&#039;&#039; that contains SQL command to add/edit/delete data.&lt;br /&gt;
*Don&#039;t use the double quote for strings (eg &#039;chaine&#039; not &amp;quot;chaine&amp;quot;) because the double quote have a specific meaning in PostGreSQL&lt;br /&gt;
&lt;br /&gt;
Example of content of a file data.sql&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
 delete from llx_const where name=&#039;MYMODULE_IT_WORKS&#039; and entity=&#039;__ENTITY__&#039;;&lt;br /&gt;
 insert into llx_const (name, value, type, note, visible, entity) values (&#039;MYMODULE_IT_WORKS&#039;,&#039;1&#039;,&#039;chaine&#039;,&#039;A constant vor my module&#039;,1,&#039;__ENTITY__&#039;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Files must be operational for the database mysql. Rem: The files of other databases are not maintained. They will be read and converted on the fly by the driver of the other database.&lt;br /&gt;
&lt;br /&gt;
===Test your .sql files===&lt;br /&gt;
&lt;br /&gt;
Once the files ready, you can return to Dolibarr to disable the module, drop those tables in the database and reactivate the module. The tables should be recreated by the activation of the module. If this is not the case, check your scripts by passing them by hand, or check the Dolibarr logs.&lt;br /&gt;
&lt;br /&gt;
===Generate the PHP DAO class===&lt;br /&gt;
Once you have created your tables into the database, move to the dev/skeletons directory and run the script&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;php build_class_from_table.php tablename modulename&amp;lt;/source&amp;gt;&lt;br /&gt;
Note: If the command does not work, try to use php-cli php instead.&lt;br /&gt;
&lt;br /&gt;
This will generate a file &#039;&#039;&#039;out.tablename.class.php&#039;&#039;&#039; that contains the class to manage table tablename. &lt;br /&gt;
In this class, you can find the CRUD methods (Create / Read / Update / Delete) already working to do an insert, a fetch (select), an update, a delete of a row in table.&lt;br /&gt;
Remove just the &amp;quot;out&amp;quot; from the file name and put the file in a subdirectory of &#039;&#039;&#039;htdocs&#039;&#039;&#039; specific to your module (in htdocs/mymodule for example).&lt;br /&gt;
&lt;br /&gt;
A file &#039;&#039;&#039;out.tablename_script.php&#039;&#039;&#039; has been generated and contains a sample code to use the class for each of the 4 CRUD methods.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since Dolibarr 6.0, the file dev/skeletons/build_class_from_table.php is no more provided. To build a class from a table you should use the ModuleBuilder modules provided as a standard module.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==The tab management (optional)==&lt;br /&gt;
&lt;br /&gt;
===Add or remove your own tabs on object sheets===&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: To add a tab on an object (invoices, orders, proposals, member ...)&lt;br /&gt;
&lt;br /&gt;
To do this go into the file descriptor of module previously created and edit the $this-&amp;gt;tabs array:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	// Array to add new pages in new tabs or remove existing one&lt;br /&gt;
	$this-&amp;gt;tabs = array(&#039;objecttype:+tabname1:Title1:mylangfile@mymodule:$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read:/mymodule/mypagetab1.php?id=__ID__&#039;    // To add a new tab identified by code tabname1&lt;br /&gt;
                            &#039;objecttype:+tabname2:Title2:mylangfile@mymodule:$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read:/mymodule/mypagetab2.php?id=__ID__&#039;,   // To add a new tab identified by code tabname2&lt;br /&gt;
                            &#039;objecttype:-tabname&#039;);                                                     // To remove an existing tab identified by code tabname&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The table should contain a list of strings, each string representing a new tab. &lt;br /&gt;
The format of the string consisting of 5 parts separated by &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
*Part 1: The element type (object type) where the tab should appear is a value from the following:&lt;br /&gt;
{{TemplateModuleTabs}}&lt;br /&gt;
&lt;br /&gt;
*Part 2: A code to identify tab to add (start with +) or to remove (start with -)&lt;br /&gt;
*Part 3: The title of the tab. This can be a hard read or better code translation in a file lang.&lt;br /&gt;
*Part 4: The name of the file &amp;quot;*.lang&amp;quot; which contains correspondence between the code translation and language to display. If this name is followed with @mymodule, Dolibarr will search translation file &amp;quot;*.lang&amp;quot; within the module, so htdocs/mymodule/langs/code_CODE/mylangfile.lang, otherwise Dolibarr will look for file htdocs/langs/code_CODE/mylangfile.lang&lt;br /&gt;
*Part 5: A condition to test if tab must be visible. Put 1 to be always visible.&lt;br /&gt;
*Part 6: The URL of the page to display when you click on the tab. The __ID__ string will be replaced automatically by the Id of the element concerned.&lt;br /&gt;
&lt;br /&gt;
To feed the contents of the tab with data from the database, see the next chapter.&lt;br /&gt;
&lt;br /&gt;
In order to get the names  &#039;tabname&#039; of existing tabs, you have to check the names used in the function &#039;product_prepare_head&#039; of the file  &#039;core/lib/module.lib.php&#039; corresponding to section &#039;$head[$h][2]&#039;.&lt;br /&gt;
&lt;br /&gt;
===Show tabs navigation into your own pages===&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: To show all standard tabs of an object (product, tiers, etc.) on your page.&lt;br /&gt;
&lt;br /&gt;
You must follow these steps :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Include files you need into your file&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For each object type, there are two files to include with line&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;require_once($url_fichier) ;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is example of files to include (DOL_DOCUMENT_ROOT is often dolibarr/htdocs/) :&lt;br /&gt;
&lt;br /&gt;
*Object thirdparty (thirdparty) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/societe/class/societe.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/company.lib.php&lt;br /&gt;
*Object product (product) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/product/class/product.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/product.lib.php&lt;br /&gt;
*Object invoice (invoice) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/compta/facture/class/facture.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/invoice.lib.php&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Create and load the object to show into your tab&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create an instance of an object of the correct class and load object from the database by using the fetch method of an object in providing to this method the id you get from URL (ie : /mytab.php?id=1).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$id=GETPOST(&#039;id&#039;,&#039;int&#039;);&lt;br /&gt;
$ref=GETPOST(&#039;ref&#039;,&#039;alpha&#039;);&lt;br /&gt;
$product = new Product($db) ;&lt;br /&gt;
$result = $product-&amp;gt;fetch($id,$ref) ; // Test $result to check the database read is ok&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Get a list of all tabs to show for your object type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Use function XXX_prepare_head($obj), where XXX is name of object. This will return an array with all definition of tab entries to show. The parameter to put into this method is the instance of an object you want tabs.&lt;br /&gt;
&lt;br /&gt;
The resulting array has the following structure&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$head        // Array of tabs&lt;br /&gt;
$head[$h]    // Element to describe one tab.&lt;br /&gt;
$head[$h][0] // Url of page to show when you click on tab&lt;br /&gt;
$head[$h][1] // Title of tab&lt;br /&gt;
$head[$h][2] // Code name to identify the tab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$head = product_prepare_head($product, $user) ; // parameter $user is present for some function anly&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. show tabs into your page&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Use function dol_fiche_head() to show all tabs defined into array $head returned by XX_prepare_head().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
dol_fiche_head($links, $active=&#039;0&#039;, $title=&#039;&#039;, $notab=0, $picto=&#039;&#039;)&lt;br /&gt;
//$links  // Tableau des onglets, appelé $head plus haut.&lt;br /&gt;
//$active // Onglet actif (mettre le nom de l&#039;onglet défini dans votre fichier de module, ou un nom contenu dans $head[$h][2]). Cet onglet sera mis en surbrillance&lt;br /&gt;
//$title  // Title to show (shown into a special tab that you can&#039;t click)&lt;br /&gt;
//$notab&lt;br /&gt;
//$picto  // Name of image to show into title. Possible values are:&lt;br /&gt;
//            product&lt;br /&gt;
//            service&lt;br /&gt;
//            company&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will show required tabs and open an html element &#039;&#039;&amp;lt; div class=&amp;quot;&amp;quot; &amp;gt;&#039;&#039; that correspond to the area under the tabs. To close area of a tab, just use &#039;&#039;&amp;lt; /div &amp;gt;&#039;&#039; into your PHP page.&lt;br /&gt;
&lt;br /&gt;
==Create or modify PHP screens (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If the purpose of your module is to add features that require new or modified screens.&lt;br /&gt;
&lt;br /&gt;
===Create a new PHP screen===&lt;br /&gt;
You must then create your PHP pages that will show/edit data from tables using the skeleton templates provided as an example in the directory &#039;&#039;&#039;modulebuilder/myobject_page.php&#039;&#039;&#039; (For the development of a script from the command line, see [[Script development]]).&lt;br /&gt;
&lt;br /&gt;
To create a new user screen, create a subdirectory of &#039;&#039;&#039;htdocs&#039;&#039;&#039; (if not already done) for your module (in &#039;&#039;&#039;htdocs/mymodule&#039;&#039;&#039; for example) to store the pages you will create.&lt;br /&gt;
&lt;br /&gt;
Copy, into that directory, the file &#039;&#039;&#039;myobject_page.phpp&#039;&#039;&#039; that will serve as a starting point for your page file.&lt;br /&gt;
Edit the file to have a correct relative path to the main.inc.php file. &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Load Dolibarr environment&lt;br /&gt;
$res=0;&lt;br /&gt;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; ! empty($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;])) $res=@include($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;].&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME&lt;br /&gt;
$tmp=empty($_SERVER[&#039;SCRIPT_FILENAME&#039;])?&#039;&#039;:$_SERVER[&#039;SCRIPT_FILENAME&#039;];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1;&lt;br /&gt;
while($i &amp;gt; 0 &amp;amp;&amp;amp; $j &amp;gt; 0 &amp;amp;&amp;amp; isset($tmp[$i]) &amp;amp;&amp;amp; isset($tmp2[$j]) &amp;amp;&amp;amp; $tmp[$i]==$tmp2[$j]) { $i--; $j--; }&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php using relative path&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res) die(&amp;quot;Include of main fails&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
As you can see, there are several tries to load the main.inc.php (or master.inc.php). The goal is to succeed in the most cases as possible. The minimum is 2 lines: one to try to load the master/main.inc.php into the dolibarr root directory and another one to try to load the file to support the case when the module is deployed into the &amp;quot;custom&amp;quot; directory. But you can have more to deal more situation. The provided example should be able to load the file main/master.inc.php in nearly all situation/setups.&lt;br /&gt;
&lt;br /&gt;
Note that you may add more &amp;quot;../&amp;quot; depending on the depth of the file relative to your module directory tree.&lt;br /&gt;
&lt;br /&gt;
It&#039;s in the main.inc.php file that is loaded technical environment variables and permissions. The following variables are objects positioned in this file:&lt;br /&gt;
&lt;br /&gt;
*$user    Object that contains the characteristics of the user + his permissions.&lt;br /&gt;
*$conf    Object that contains Dolibarr configuration.&lt;br /&gt;
*$db      Object that contains an opened connection handler to the database.&lt;br /&gt;
*$langs   Object that contains the user&#039;s language.&lt;br /&gt;
&lt;br /&gt;
Then enter your code to display the page.&lt;br /&gt;
&lt;br /&gt;
*To include a class or library dedicated to the module is done using a Dolibarr function (and not using directly include_once):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
dol_include_once(&#039;/mymodule/class/myclass.class.php&#039;, &#039;MyClass&#039;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*To include classes provided with Dolibarr, use the following syntax:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
require_once DOL_DOCUMENT_ROOT.&#039;/core/class/doli.class.php&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Add some fields into existing forms===&lt;br /&gt;
You may want to provide a module that adds more fields into forms (input and view) of some elements. &lt;br /&gt;
&lt;br /&gt;
A heavy solution (but not so bad) may be to replace all pages used to create element (this means to disable the &amp;quot;New element&amp;quot; menu entry and adding yours, and disable tab that shows element to replace with a tab that is your own full page (copied/pasted from original) to do same than original page but modified to add your fields and stored added data into your own table). Go to menu [[#Define your entries in the menu (optional)]] and [[#The tab management (optional)]] if this solution suits you (this solution is more powerful since you can change everything you want into the page). &lt;br /&gt;
&lt;br /&gt;
We will describe here another solution, that works only to &amp;quot;add fields&amp;quot; at end of existing fields, using the element &amp;quot;category&amp;quot; as an example but you can convert this tutorial for invoice, proposal ...&lt;br /&gt;
&lt;br /&gt;
*First thing is to add a table, owned by your module, to store the value of new fields. This table will have only one column called &amp;quot;rowid&amp;quot; (will contain the same value than field rowid of element table) + one column for each new field you want to add. Then create a class with CRUD (Create/Read/Update/Delete) methods for this new table. For this two tasks, go back to previous chapter [[#Create your SQL tables and the PHP DAO class]].&lt;br /&gt;
*Next step is to add a hook into your module to add the new fields into the form. See chapter [[Hooks_system#Implement_the_Hook]] for generic documentation to use hooks.&lt;br /&gt;
&lt;br /&gt;
If you follow this tutorial, to be able to add fields into category forms, you must do:&lt;br /&gt;
{{ToComplete}}&lt;br /&gt;
&lt;br /&gt;
===Replace parts of screen that are templated (version 3.3+)===&lt;br /&gt;
Some parts of Dolibarr screen are isolated into native PHP template files.&lt;br /&gt;
You can develop a module to overwrite such templates with yours.&lt;br /&gt;
{{ToComplete}}&lt;br /&gt;
&lt;br /&gt;
===Add/replace part of fields supported by hooks===&lt;br /&gt;
See chapter [[Hooks_system#Implement_the_Hook]] to know how to use Dolibarr existing hooks to add/replace code at Dolibarr hooks place.&lt;br /&gt;
&lt;br /&gt;
===Database access===&lt;br /&gt;
If you need to edit some data in the database inside your own table, use the PHP class generated before.&lt;br /&gt;
&lt;br /&gt;
If you to make access to tables with no dedicated PHP class available, this is always possible (for example if you want to get a list of records with a particular join or filter). In this case, this is a code samples to follow:&lt;br /&gt;
&lt;br /&gt;
To make an insert, update or delete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$db-&amp;gt;begin();   // Start transaction&lt;br /&gt;
$db-&amp;gt;query(&amp;quot;My SQL request insert, update or delete&amp;quot;);&lt;br /&gt;
$db-&amp;gt;commit();       // Validate transaction&lt;br /&gt;
or $db-&amp;gt;rollback()  // Cancel transaction&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To read:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$resql=$db-&amp;gt;query(&amp;quot;My select request&amp;quot;);&lt;br /&gt;
if ($resql)&lt;br /&gt;
{&lt;br /&gt;
	$num = $db-&amp;gt;num_rows($resql);&lt;br /&gt;
	$i = 0;&lt;br /&gt;
	if ($num)&lt;br /&gt;
	{&lt;br /&gt;
		while ($i &amp;lt; $num)&lt;br /&gt;
		{&lt;br /&gt;
			$obj = $db-&amp;gt;fetch_object($resql);&lt;br /&gt;
			if ($obj)&lt;br /&gt;
			{&lt;br /&gt;
				// You can use here results&lt;br /&gt;
				print $obj-&amp;gt;field1;&lt;br /&gt;
				print $obj-&amp;gt;field2;&lt;br /&gt;
			}&lt;br /&gt;
			$i++;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Define style of your pages===&lt;br /&gt;
To have the look of your own pages to match the Dolibarr theme, it is necessary to use the Dolibarr CSS styles.&lt;br /&gt;
&lt;br /&gt;
You can use for example:&lt;br /&gt;
&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;liste_titre&#039;&#039;&#039;&amp;quot; on tags &#039;&#039;tr&#039;&#039; and &#039;&#039;td&#039;&#039; for the head row of a table.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;pair&#039;&#039;&#039;&amp;quot; or class=&amp;quot;&#039;&#039;&#039;impair&#039;&#039;&#039;&amp;quot; on tags &#039;&#039;tr&#039;&#039; and &#039;&#039;td&#039;&#039; of other rows of a table.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;flat&#039;&#039;&#039;&amp;quot; on all input fields (&#039;&#039;input, select, textarea&#039;&#039;...).&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;button&#039;&#039;&#039;&amp;quot; on HTML fields with type &#039;&#039;input type=&amp;quot;submit&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Use the Dolibarr date picker===&lt;br /&gt;
If you want to use the Dolibarr date selector (with its calendar popup) into your pages, use the following line:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $form=new Form($db);&lt;br /&gt;
 $form-&amp;gt;select_date(&#039;&#039;,&#039;mykey&#039;,0,0,0,&amp;quot;myform&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The string mykey will identify the date selector in the form. You must use different values if you use several date selectors in same page.&lt;br /&gt;
The string myform is the name of the FORM in which the selector is included (value found in the form name=&amp;quot;myform&amp;quot; in HTML page).&lt;br /&gt;
This means a date selector must be included necessarily into an html FORM.&lt;br /&gt;
&lt;br /&gt;
To get value after the POST of your form, the command is:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mydate = dol_mktime(12, 0 , 0, $_POST[&#039;mykeymonth&#039;], $_POST[&#039;mykeyday&#039;], $_POST[&#039;mykeyyear&#039;]);&lt;br /&gt;
print strftime(&#039;%A %d %B %Y&#039;, $mydate);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Add your own setup page (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs parameters, which are to be provided by the user, for proper setting up of the module.&lt;br /&gt;
&lt;br /&gt;
===Create your page to edit parameters===&lt;br /&gt;
If your module needs several parameters to be setup, you must create a page to edit options (these options will be saved in the [[Table llx_const|table &#039;&#039;&#039;llx_const&#039;&#039;&#039;]]).&lt;br /&gt;
Create a page named &#039;&#039;&#039;mymodule_setuppage.php&#039;&#039;&#039; that shows a form for possible options to update them into the above-mentioned table.&lt;br /&gt;
It is necessary to take an example from a page of the directory &#039;&#039;&#039;/admin&#039;&#039;&#039; that will show you the way to read/save your parameters.&lt;br /&gt;
Put this PHP page into the directory &#039;&#039;&#039;/admin&#039;&#039;&#039; of your module (e.g. mymodule/admin/mymodule_setuppage.php).&lt;br /&gt;
&lt;br /&gt;
===Modify the descriptor file of your module===&lt;br /&gt;
Then, within the descriptor file of your module, modify the variable &#039;&#039;&#039;config_page_url&#039;&#039;&#039; to set the name of this PHP page.&lt;br /&gt;
If the page is in the directory &#039;&#039;&#039;admin/&#039;&#039;&#039;, then the path is not required, e.g. like this:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;mymodule_setuppage.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the page is in the directory &#039;&#039;&#039;mymodule/admin/&#039;&#039;&#039;, then like this:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;mymodule_setuppage.php@mymodule&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Test your page===&lt;br /&gt;
Go into page &#039;&#039;&#039;Home-&amp;gt;Setup-&amp;gt;Modules&#039;&#039;&#039;, you should see a picture at the end of the line of your module to reach your setup page. Click on it, you should be able to view/edit parameters from your page.&lt;br /&gt;
&lt;br /&gt;
==Define your entries in menu (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you have created PHP pages, it is necessary that those pages can be reached from menu entries in Dolibarr menu.&lt;br /&gt;
&lt;br /&gt;
===Define your menu entries===&lt;br /&gt;
For this, you must define into the module descriptor, the array this-&amp;gt;menu that declares all menus added by your module.&lt;br /&gt;
This array contains entries that will appear once your module is activated.&lt;br /&gt;
The example module descriptor file &#039;&#039;&#039;modMyModule.class.php&#039;&#039;&#039; contains an example to declare a top menu and also its left menu entries.&lt;br /&gt;
&lt;br /&gt;
This is the example of code to declare your own menu entries in a module descriptor file:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Main menu entries&lt;br /&gt;
$this-&amp;gt;menu = array();			// List of menus to add&lt;br /&gt;
$r=0;&lt;br /&gt;
&lt;br /&gt;
// Add here entries to declare new menus&lt;br /&gt;
// Example to declare the Top Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;0,			// Put 0 if this is a top menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;top&#039;,			// This is a Top menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MyModule top menu&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;mymodule&#039;,&lt;br /&gt;
			&#039;leftmenu&#039;=&amp;gt;&#039;mymodule&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/mymodule/pagetop.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;mymodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users, 1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&lt;br /&gt;
// Example to declare a Left Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;&#039;fk_mainmenu=xxx&#039;,		    // Use &#039;fk_mainmenu=xxx&#039; or &#039;fk_mainmenu=xxx,fk_leftmenu=yyy&#039; where xxx is mainmenucode and yyy is a leftmenucode of parent menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;left&#039;,			        // This is a Left menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MyModule left menu 1&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;xxx&#039;,&lt;br /&gt;
                        &#039;leftmenu&#039;=&amp;gt;&#039;yyy&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/mymodule/pagelevel1.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;mymodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users,1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To show the menu or not depending on a permission, modify property &#039;&#039;&#039;perms&#039;&#039;&#039; in the array. See chapter on permissions later to see how to add permissions.&lt;br /&gt;
&lt;br /&gt;
===Test your menu entries===&lt;br /&gt;
Disable and re-enable your module under the Dolibarr module setup page, menus entries must appear (if property &#039;enabled&#039; is declaration array is ok).&lt;br /&gt;
&lt;br /&gt;
==Add your own permissions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you want to add new permissions.&lt;br /&gt;
&lt;br /&gt;
The way to define permissions that will manage your module is done inside the module descriptor created previously.&lt;br /&gt;
Modify line &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights_class = &#039;mymodule&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
with correct value for mymodule.&lt;br /&gt;
&lt;br /&gt;
Then you must fill the array $this-&amp;gt;rights with as many entries than different permissions you need to manage.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights[$r][0] = 10001;&lt;br /&gt;
$this-&amp;gt;rights[$r][1] = &#039;Label by default of permission&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][2] = &#039;r&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][3] = 1;&lt;br /&gt;
$this-&amp;gt;rights[$r][4] = &#039;action&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][5] = &#039;subaction&#039;;&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Into $this-&amp;gt;rights[$r][0], put a permission id not already used (See into menu &#039;&#039;&#039;System info&#039;&#039;&#039; on a working installation of Dolibarr to know list of id already used by standard modules.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][1], put a label by default for permission (This label will be used if no translation can be found into the file &#039;&#039;&#039;admin.lang&#039;&#039;&#039; Translation key should be &amp;quot;Permission10001=My permission Label&amp;quot;).&lt;br /&gt;
Into $this-&amp;gt;rights[$r][2], types of the permission. There are three type of permission, &#039;r&#039; for read, list or expert permission, &#039;w&#039; for write or update permission and &#039;d&#039; for delete permission.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][3], put 1 if this permission must be granted automatically by default to any newly created user.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][4] and $this-&amp;gt;rights[$r][5], put an action and subaction string without spaces. You will be able to test if a user has the permission in your PHP source code with the sequence:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;action-&amp;gt;subaction) ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Define your own box (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs to provide one or several new boxes to show on home page.&lt;br /&gt;
&lt;br /&gt;
===Define your box===&lt;br /&gt;
For this, modify the array $this-&amp;gt;boxes into the module descriptor file.&lt;br /&gt;
All you have to do is to add 2 lines for each box file you will create into directory &#039;&#039;&#039;htdocs/mymodule/core/boxes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example:&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;file&#039;]=&#039;mybox0.php@mymodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;note&#039;]=&#039;My box 0&#039;&lt;br /&gt;
 ...&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;file&#039;]=&#039;myboxn.php@mymodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;note&#039;]=&#039;My box n&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then create files &#039;&#039;&#039;htdocs/mymodule/core/boxes/mybox0.php&#039;&#039;&#039;, &#039;&#039;&#039;htdocs/mymodule/core/boxes/mybox1.php&#039;&#039;&#039;... by copying an example from an existing box file (found into directory &#039;&#039;&#039;htdocs/core/boxes&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
===Test if your box is detected by Dolibarr===&lt;br /&gt;
Disable and enabled module.&lt;br /&gt;
&lt;br /&gt;
Go into menu &#039;&#039;&#039;Home - Setup - Boxes&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Your boxes must appear in the list of boxes you can activate. Activate the box and go on the home page to see if the box is showing correctly.&lt;br /&gt;
&lt;br /&gt;
==Define your own export (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module provides new predefined database export profiles (for its own tables or for already existing tables of another module).&lt;br /&gt;
&lt;br /&gt;
===Define export===&lt;br /&gt;
For this uncomment and modify arrays $this-&amp;gt;export_xxx in your module descriptor file.&lt;br /&gt;
&lt;br /&gt;
===Test your export===&lt;br /&gt;
Go into menu Tools -&amp;gt; Export. Your export will appear in the list of available predefined exports (if your module is enabled).&lt;br /&gt;
Choose it, you must see a list of all possible fields defined in the export arrays.&lt;br /&gt;
Choose on field and try to build an export file. If ok, try again with all fields.&lt;br /&gt;
&lt;br /&gt;
==Define your CSS styles (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If in your PHP pages, you use class styles that are not defined inside Dolibarr themes CSS (not recommanded).&lt;br /&gt;
&lt;br /&gt;
===Create and declare your style sheet===&lt;br /&gt;
Create a style sheet CSS named &#039;&#039;&#039;mymodule.css&#039;&#039;&#039; or &#039;&#039;&#039;mymodule.css.php&#039;&#039;&#039; and put it into directory &#039;&#039;&#039;htdocs/mymodule&#039;&#039;&#039;. You can have several CSS files per module.&lt;br /&gt;
Remember it&#039;s better to use existing styles already available by default into Dolibarr (The CSS file used by Dolibarr is file &#039;&#039;&#039;themes/mytheme/&#039;&#039;themename&#039;&#039;.css.php&#039;&#039;&#039;. Create your own CSS files only if you need absolutely to add not already existing styles.&lt;br /&gt;
&lt;br /&gt;
Once your style sheets are ready, declare them into your module descriptor file by modifying the property &#039;&#039;&#039;$this-&amp;gt;modules_parts&#039;&#039;&#039;.&lt;br /&gt;
Value to put here must be an array of relative URLs to your CSS files.&lt;br /&gt;
For example&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;module_parts = array(&#039;css&#039; =&amp;gt; array(&#039;/mymodule/css/mymodule.css.php&#039;,&#039;/mymodule/css/myother.css&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Test your style sheet===&lt;br /&gt;
Disable and enable your module.&lt;br /&gt;
&lt;br /&gt;
Go on the home page (index.php). Show the HTML source of the page.&lt;br /&gt;
&lt;br /&gt;
You should see into the HTML header, a line that declares your style sheet.&lt;br /&gt;
&lt;br /&gt;
==Add your Javascript functions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If in your PHP pages, you use javascript functions not available in Dolibarr (in file lib_head.js)&lt;br /&gt;
&lt;br /&gt;
If you need to use your own javascript functions inside your PHP pages, it is necessary to have your functions, defined into your javascript file &#039;&#039;&#039;htdocs/mymodule/js/mymodule.js&#039;&#039;&#039;, included into the HTML HEAD section.&lt;br /&gt;
To ask Dolibarr that forge this header to include your own javascript file, you must just provide it to the llxHeader() function called by your page.&lt;br /&gt;
&lt;br /&gt;
Example for page /htdocs/mymodule/mypage.php :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$morejs=array(&amp;quot;/mymodule/js/mymodule.js&amp;quot;);&lt;br /&gt;
llxHeader(&#039;&#039;,&#039;Titre&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,$morejs,&#039;&#039;,0,0); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Run your own code on any Dolibarr event (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you want to execute your own code once a common Dolibarr event has occurred (example: I want to update a table in my module when an invoice is created into Dolibarr), you must create a &#039;&#039;&#039;triggers&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
See also [[Interfaces_Dolibarr_toward_foreign_systems]]&lt;br /&gt;
and [[Interfaces_from_foreign_systems_toward_Dolibarr]]&lt;br /&gt;
&lt;br /&gt;
==Insert your code inside Dolibarr hooks positions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to add code or replace Dolibarr code into another situation than a business event (See the previous chapter for adding code during a business event).&lt;br /&gt;
&lt;br /&gt;
See page [[Hooks_system]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Add your own numbering rules==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you need a new rule for generated ref of elements that are not covered by existing rules.&lt;br /&gt;
&lt;br /&gt;
See page [[Create numbering module]].&lt;br /&gt;
&lt;br /&gt;
==Add your document template (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to personalized your own generated PDF or ODT documents.&lt;br /&gt;
&lt;br /&gt;
Note: To add this feature you don&#039;t need to create a module descriptor.&lt;br /&gt;
&lt;br /&gt;
Documentation to add your own template is available on page [[Create_a_PDF_document_template]] or [[Create_an_ODT_document_template]].&lt;br /&gt;
&lt;br /&gt;
==Add your skin (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to personalized your colors/fonts/images.&lt;br /&gt;
&lt;br /&gt;
Note: To add this feature you don&#039;t need to create a module descriptor.&lt;br /&gt;
&lt;br /&gt;
To add your own skin, read page [[Skins]].&lt;br /&gt;
&lt;br /&gt;
=Some coding rules and predefined functions=&lt;br /&gt;
The coding rules to be followed are defined in the [[Developer documentation]], under section &amp;quot;General Information - Language and standards development&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A lot of predefined features for developers are also available and described into page [[Developer documentation]] under section &amp;quot;Technical components of Dolibarr&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=Create a package to distribute and install your module=&lt;br /&gt;
This process must be used to generate a package to submit it on the http://www.dolistore.com marketplace.&lt;br /&gt;
But you can use it to have a package easy to distribute on your own network.&lt;br /&gt;
&lt;br /&gt;
*Go into the directory &#039;&#039;&#039;/build&#039;&#039;&#039; and copy the file &#039;&#039;&#039;makepack-dolibarrmodules.conf&#039;&#039;&#039; into &#039;&#039;&#039;makepack-mymodule.conf&#039;&#039;&#039;. Warning, this directory may not be provided in some packages of stable versions. If so, it can be retrieved from the snapshot available for download on the Dolibarr website in area &amp;quot;Development version&amp;quot; (taken in this case the whole build directory which is autonomous and independent directory).&lt;br /&gt;
&lt;br /&gt;
Edit this file to add a list of file names for all new files you created for your module (module descriptor, new sql tables files, php page, images, etc...)&lt;br /&gt;
&lt;br /&gt;
*Run the script via Perl (need the Perl version 5.0 or later):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
perl makepack-dolibarrmodule.pl&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The script asks you the name of your module, its major and minor version. A file &#039;&#039;&#039;mymodule.zip &#039;&#039;&#039; will then be manufactured containing your module ready to be deployed.&lt;br /&gt;
&lt;br /&gt;
*The person who receives your module must then place the file in the root directory of a Dolibarr installation and perform the command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tar -xvf mymodule.zip&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*If you want your module to be public, you can submit it (the zip file) on Dolibarr marketplace website: {{LinkToPluginDownload}} (you must create an account first and be logged to use the link &amp;quot;Submit a module/product&amp;quot;).&lt;br /&gt;
**If your module was built correctly, the file will be validated later.&lt;br /&gt;
**If quality is enough and license permits it, the code might be added inside main Dolibarr sources (except if you disagree for that).&lt;br /&gt;
&lt;br /&gt;
=Enabling/activation condition of external module on DoliStore=&lt;br /&gt;
&lt;br /&gt;
See [[Module_Dolistore_Validation_Rules|Validation Rules]]&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>ALSOFT</name></author>
	</entry>
	<entry>
		<id>https://wiki.dolibarr.org/index.php?title=Module_development&amp;diff=49921</id>
		<title>Module development</title>
		<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php?title=Module_development&amp;diff=49921"/>
		<updated>2021-03-09T07:18:45Z</updated>

		<summary type="html">&lt;p&gt;ALSOFT: /* Create a new PHP screen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- BEGIN origin interlang links --&amp;gt;&lt;br /&gt;
&amp;lt;!-- You can edit this section but do NOT remove these comments&lt;br /&gt;
     Links below will be automatically replicated on translated pages by PolyglotBot --&amp;gt;&lt;br /&gt;
[[fr:Développement_module]]&lt;br /&gt;
[[es:Desarrollo_de_un_módulo]]&lt;br /&gt;
[[de:Modul_Entwicklung]]&lt;br /&gt;
[[zh:模块开发]]&lt;br /&gt;
&amp;lt;!-- END interlang links --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
{{TemplateDocDevEn}}&lt;br /&gt;
&lt;br /&gt;
To create a new module/addon for Dolibarr, there is several steps. This tutorial will describe you each of them to build a module to extend Dolibarr features, like one or several of the following :&lt;br /&gt;
&lt;br /&gt;
*Add new tables in database&lt;br /&gt;
*Add your own menu entries&lt;br /&gt;
*Add new screens to edit new tables&lt;br /&gt;
*Add or remove tabs on object view (invoice, product, order, event, ...)&lt;br /&gt;
*Add predefined exports for the internal export tool&lt;br /&gt;
*Add new information boxes in the home page&lt;br /&gt;
*Add new substitutions variables&lt;br /&gt;
*Define new permissions&lt;br /&gt;
*Execute code automatically triggered by a particular Dolibarr action&lt;br /&gt;
*Insert your code inside Dolibarr hooks positions&lt;br /&gt;
*Add your numbering module&lt;br /&gt;
*Add a new document template&lt;br /&gt;
*Add a new skin&lt;br /&gt;
&lt;br /&gt;
etc...&lt;br /&gt;
&lt;br /&gt;
Following chapters presents how to do all of this manually with an easy way.&lt;br /&gt;
&lt;br /&gt;
=Module creation with the module builder=&lt;br /&gt;
From Dolibarr 9.0 it is possible to create the main pages of your module with the Module Builder. To activate it, go into the list of module and enable the module &amp;quot;Module Builder&amp;quot;, then click on the &amp;quot;bug&amp;quot; image in the top right of screen.&lt;br /&gt;
&lt;br /&gt;
=Example of Template External Module=&lt;br /&gt;
A good model to start development of external module can be found here : [https://github.com/Dolibarr/dolibarr/tree/develop/htdocs/modulebuilder/template GitHub Dolibarr Module Modèle]&lt;br /&gt;
&lt;br /&gt;
=Create your module=&lt;br /&gt;
==Create a Module descriptor for your Module (required)==&lt;br /&gt;
&#039;&#039;&#039;When it is required&#039;&#039;&#039;: Required as soon as an addon is developed, whatever its goal is (except for adding a skin).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since Dolibarr 9.0, you should use the ModuleBuilder module provided as a standard module to generate the module descriptor&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Create your module descriptor===&lt;br /&gt;
The first step is to create a file descriptor for the module. &lt;br /&gt;
&lt;br /&gt;
*Create directory &#039;&#039;&#039;/htdocs/&#039;&#039;mymodule&#039;&#039;/core/modules&#039;&#039;&#039;. Then copy the file modMyModule.class.php from the directory dev/skeletons into this directory &#039;&#039;&#039;htdocs/&#039;&#039;mymodule&#039;&#039;/core/modules&#039;&#039;&#039;. Change the name of the file modMyModule.class.php to the name corresponding to the purpose of your module. Name of the file must start with initial &#039;mod&#039; and end with .class.php (for example if you want to give the name &#039;NewName&#039; to this file, then the name should be &#039;modNewName.class.php&#039;).&lt;br /&gt;
&lt;br /&gt;
Next modify the contents of this file as follows:&lt;br /&gt;
&lt;br /&gt;
*Replace all &amp;quot;modMyModule&amp;quot; with a value which corresponds to the purpose of your module. This value must always start with &#039;mod&#039; and contain only alpha characters (again, if the name given to the file was &#039;NewName&#039;, then replace all &amp;quot;modMyModule&amp;quot; with &amp;quot;modNewName&amp;quot;).&lt;br /&gt;
*Change the number in: $this-&amp;gt;numero = 100000 by a number that designates your module id. To avoid conflicts with other modules, you can consult the page that lists already reserved id numbers: [[List of modules id|List of modules id]].&lt;br /&gt;
*Modify any other variables defined in the constructor (see comment in the code skeleton for their meaning).&lt;br /&gt;
&lt;br /&gt;
Your file descriptor for your module is ready. See the next step to activate it.&lt;br /&gt;
&lt;br /&gt;
===Test your descriptor===&lt;br /&gt;
&lt;br /&gt;
Launch Dolibarr and go to page &#039;&#039;&#039;Setup-&amp;gt;module&#039;&#039;&#039;? &lt;br /&gt;
If you set the property version in the module description you should see a new line with your new module and the possibility to activate it or not. If you set the property version to &amp;quot;develop&amp;quot; or &amp;quot;experiental&amp;quot;, to see your module, you must first go into &#039;&#039;&#039;Setup-Others&#039;&#039;&#039; and set MAIN_FEATURES_LEVEL to 1 to see &amp;quot;experimental&amp;quot; modules or 2 to see &amp;quot;development&amp;quot; modules.&lt;br /&gt;
&lt;br /&gt;
==Tree of path for new module files (required)==&lt;br /&gt;
This is how your files must be organized when building a new module (the zip file must also match this rule).&lt;br /&gt;
Note: Only the second line is mandatory.&lt;br /&gt;
&lt;br /&gt;
{{TemplateModuleTreeSimple}}&lt;br /&gt;
&lt;br /&gt;
==Create your SQL tables and the PHP DAO class (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs to manage data of its own&lt;br /&gt;
&lt;br /&gt;
===Create your .sql file===&lt;br /&gt;
If your module is designed to manage data of its own, which are not available in the standard version of Dolibarr, it is necessary to define SQL tables to store the data.&lt;br /&gt;
&lt;br /&gt;
Scripts for creating tables and load data by your own module are saved into a subdirectory called &amp;quot;/mymodule/sql&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Then check into your descriptor file, into function &#039;&#039;&#039;init&#039;&#039;&#039; that the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;$this-&amp;gt;_load_tables(&#039;/mymodule/sql/&#039;);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
is not commented.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Rules to follow:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Add the files about creating tables commands on the principle of a file &#039;&#039;&#039;llx_matable.sql&#039;&#039;&#039; per table, with a possibly file &#039;&#039;&#039;llx_matable.key.sql&#039;&#039;&#039; (see existing files in &#039;&#039;&#039;install/mysql/tables&#039;&#039;&#039; for examples).&lt;br /&gt;
*The recommended type and name for SQL fields are defined into page [[Language_and_development_rules#Table_and_fields_structures]].&lt;br /&gt;
*To manage data, you must create a file called &#039;&#039;&#039;data.sql&#039;&#039;&#039; inside directory &#039;&#039;&#039;/mymodule/sql/&#039;&#039;&#039; that contains SQL command to add/edit/delete data.&lt;br /&gt;
*Don&#039;t use the double quote for strings (eg &#039;chaine&#039; not &amp;quot;chaine&amp;quot;) because the double quote have a specific meaning in PostGreSQL&lt;br /&gt;
&lt;br /&gt;
Example of content of a file data.sql&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
 delete from llx_const where name=&#039;MYMODULE_IT_WORKS&#039; and entity=&#039;__ENTITY__&#039;;&lt;br /&gt;
 insert into llx_const (name, value, type, note, visible, entity) values (&#039;MYMODULE_IT_WORKS&#039;,&#039;1&#039;,&#039;chaine&#039;,&#039;A constant vor my module&#039;,1,&#039;__ENTITY__&#039;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Files must be operational for the database mysql. Rem: The files of other databases are not maintained. They will be read and converted on the fly by the driver of the other database.&lt;br /&gt;
&lt;br /&gt;
===Test your .sql files===&lt;br /&gt;
&lt;br /&gt;
Once the files ready, you can return to Dolibarr to disable the module, drop those tables in the database and reactivate the module. The tables should be recreated by the activation of the module. If this is not the case, check your scripts by passing them by hand, or check the Dolibarr logs.&lt;br /&gt;
&lt;br /&gt;
===Generate the PHP DAO class===&lt;br /&gt;
Once you have created your tables into the database, move to the dev/skeletons directory and run the script&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;php build_class_from_table.php tablename modulename&amp;lt;/source&amp;gt;&lt;br /&gt;
Note: If the command does not work, try to use php-cli php instead.&lt;br /&gt;
&lt;br /&gt;
This will generate a file &#039;&#039;&#039;out.tablename.class.php&#039;&#039;&#039; that contains the class to manage table tablename. &lt;br /&gt;
In this class, you can find the CRUD methods (Create / Read / Update / Delete) already working to do an insert, a fetch (select), an update, a delete of a row in table.&lt;br /&gt;
Remove just the &amp;quot;out&amp;quot; from the file name and put the file in a subdirectory of &#039;&#039;&#039;htdocs&#039;&#039;&#039; specific to your module (in htdocs/mymodule for example).&lt;br /&gt;
&lt;br /&gt;
A file &#039;&#039;&#039;out.tablename_script.php&#039;&#039;&#039; has been generated and contains a sample code to use the class for each of the 4 CRUD methods.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since Dolibarr 6.0, the file dev/skeletons/build_class_from_table.php is no more provided. To build a class from a table you should use the ModuleBuilder modules provided as a standard module.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==The tab management (optional)==&lt;br /&gt;
&lt;br /&gt;
===Add or remove your own tabs on object sheets===&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: To add a tab on an object (invoices, orders, proposals, member ...)&lt;br /&gt;
&lt;br /&gt;
To do this go into the file descriptor of module previously created and edit the $this-&amp;gt;tabs array:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	// Array to add new pages in new tabs or remove existing one&lt;br /&gt;
	$this-&amp;gt;tabs = array(&#039;objecttype:+tabname1:Title1:mylangfile@mymodule:$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read:/mymodule/mypagetab1.php?id=__ID__&#039;    // To add a new tab identified by code tabname1&lt;br /&gt;
                            &#039;objecttype:+tabname2:Title2:mylangfile@mymodule:$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read:/mymodule/mypagetab2.php?id=__ID__&#039;,   // To add a new tab identified by code tabname2&lt;br /&gt;
                            &#039;objecttype:-tabname&#039;);                                                     // To remove an existing tab identified by code tabname&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The table should contain a list of strings, each string representing a new tab. &lt;br /&gt;
The format of the string consisting of 5 parts separated by &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
*Part 1: The element type (object type) where the tab should appear is a value from the following:&lt;br /&gt;
{{TemplateModuleTabs}}&lt;br /&gt;
&lt;br /&gt;
*Part 2: A code to identify tab to add (start with +) or to remove (start with -)&lt;br /&gt;
*Part 3: The title of the tab. This can be a hard read or better code translation in a file lang.&lt;br /&gt;
*Part 4: The name of the file &amp;quot;*.lang&amp;quot; which contains correspondence between the code translation and language to display. If this name is followed with @mymodule, Dolibarr will search translation file &amp;quot;*.lang&amp;quot; within the module, so htdocs/mymodule/langs/code_CODE/mylangfile.lang, otherwise Dolibarr will look for file htdocs/langs/code_CODE/mylangfile.lang&lt;br /&gt;
*Part 5: A condition to test if tab must be visible. Put 1 to be always visible.&lt;br /&gt;
*Part 6: The URL of the page to display when you click on the tab. The __ID__ string will be replaced automatically by the Id of the element concerned.&lt;br /&gt;
&lt;br /&gt;
To feed the contents of the tab with data from the database, see the next chapter.&lt;br /&gt;
&lt;br /&gt;
In order to get the names  &#039;tabname&#039; of existing tabs, you have to check the names used in the function &#039;product_prepare_head&#039; of the file  &#039;core/lib/module.lib.php&#039; corresponding to section &#039;$head[$h][2]&#039;.&lt;br /&gt;
&lt;br /&gt;
===Show tabs navigation into your own pages===&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: To show all standard tabs of an object (product, tiers, etc.) on your page.&lt;br /&gt;
&lt;br /&gt;
You must follow these steps :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Include files you need into your file&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For each object type, there are two files to include with line&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;require_once($url_fichier) ;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is example of files to include (DOL_DOCUMENT_ROOT is often dolibarr/htdocs/) :&lt;br /&gt;
&lt;br /&gt;
*Object thirdparty (thirdparty) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/societe/class/societe.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/company.lib.php&lt;br /&gt;
*Object product (product) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/product/class/product.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/product.lib.php&lt;br /&gt;
*Object invoice (invoice) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/compta/facture/class/facture.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/invoice.lib.php&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Create and load the object to show into your tab&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create an instance of an object of the correct class and load object from the database by using the fetch method of an object in providing to this method the id you get from URL (ie : /mytab.php?id=1).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$id=GETPOST(&#039;id&#039;,&#039;int&#039;);&lt;br /&gt;
$ref=GETPOST(&#039;ref&#039;,&#039;alpha&#039;);&lt;br /&gt;
$product = new Product($db) ;&lt;br /&gt;
$result = $product-&amp;gt;fetch($id,$ref) ; // Test $result to check the database read is ok&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Get a list of all tabs to show for your object type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Use function XXX_prepare_head($obj), where XXX is name of object. This will return an array with all definition of tab entries to show. The parameter to put into this method is the instance of an object you want tabs.&lt;br /&gt;
&lt;br /&gt;
The resulting array has the following structure&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$head        // Array of tabs&lt;br /&gt;
$head[$h]    // Element to describe one tab.&lt;br /&gt;
$head[$h][0] // Url of page to show when you click on tab&lt;br /&gt;
$head[$h][1] // Title of tab&lt;br /&gt;
$head[$h][2] // Code name to identify the tab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$head = product_prepare_head($product, $user) ; // parameter $user is present for some function anly&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. show tabs into your page&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Use function dol_fiche_head() to show all tabs defined into array $head returned by XX_prepare_head().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
dol_fiche_head($links, $active=&#039;0&#039;, $title=&#039;&#039;, $notab=0, $picto=&#039;&#039;)&lt;br /&gt;
//$links  // Tableau des onglets, appelé $head plus haut.&lt;br /&gt;
//$active // Onglet actif (mettre le nom de l&#039;onglet défini dans votre fichier de module, ou un nom contenu dans $head[$h][2]). Cet onglet sera mis en surbrillance&lt;br /&gt;
//$title  // Title to show (shown into a special tab that you can&#039;t click)&lt;br /&gt;
//$notab&lt;br /&gt;
//$picto  // Name of image to show into title. Possible values are:&lt;br /&gt;
//            product&lt;br /&gt;
//            service&lt;br /&gt;
//            company&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will show required tabs and open an html element &#039;&#039;&amp;lt; div class=&amp;quot;&amp;quot; &amp;gt;&#039;&#039; that correspond to the area under the tabs. To close area of a tab, just use &#039;&#039;&amp;lt; /div &amp;gt;&#039;&#039; into your PHP page.&lt;br /&gt;
&lt;br /&gt;
==Create or modify PHP screens (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If the purpose of your module is to add features that require new or modified screens.&lt;br /&gt;
&lt;br /&gt;
===Create a new PHP screen===&lt;br /&gt;
You must then create your PHP pages that will show/edit data from tables using the skeleton templates provided as an example in the directory &#039;&#039;&#039;modulebuilder/myobject_page.php&#039;&#039;&#039; (For the development of a script from the command line, see [[Script development]]).&lt;br /&gt;
&lt;br /&gt;
To create a new user screen, create a subdirectory of &#039;&#039;&#039;htdocs&#039;&#039;&#039; (if not already done) for your module (in &#039;&#039;&#039;htdocs/mymodule&#039;&#039;&#039; for example) to store the pages you will create.&lt;br /&gt;
&lt;br /&gt;
Copy, into that directory, the file &#039;&#039;&#039;myobject_page.phpp&#039;&#039;&#039; that will serve as a starting point for your page file.&lt;br /&gt;
Edit the file to have a correct relative path to the main.inc.php file. &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Load Dolibarr environment&lt;br /&gt;
$res=0;&lt;br /&gt;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; ! empty($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;])) $res=@include($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;].&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME&lt;br /&gt;
$tmp=empty($_SERVER[&#039;SCRIPT_FILENAME&#039;])?&#039;&#039;:$_SERVER[&#039;SCRIPT_FILENAME&#039;];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1;&lt;br /&gt;
while($i &amp;gt; 0 &amp;amp;&amp;amp; $j &amp;gt; 0 &amp;amp;&amp;amp; isset($tmp[$i]) &amp;amp;&amp;amp; isset($tmp2[$j]) &amp;amp;&amp;amp; $tmp[$i]==$tmp2[$j]) { $i--; $j--; }&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php using relative path&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res) die(&amp;quot;Include of main fails&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
As you can see, there are several tries to load the main.inc.php (or master.inc.php). The goal is to succeed in the most cases as possible. The minimum is 2 lines: one to try to load the master/main.inc.php into the dolibarr root directory and another one to try to load the file to support the case when the module is deployed into the &amp;quot;custom&amp;quot; directory. But you can have more to deal more situation. The provided example should be able to load the file main/master.inc.php in nearly all situation/setups.&lt;br /&gt;
&lt;br /&gt;
Note that you may add more &amp;quot;../&amp;quot; depending on the depth of the file relative to your module directory tree.&lt;br /&gt;
&lt;br /&gt;
It&#039;s in the main.inc.php file that is loaded technical environment variables and permissions. The following variables are objects positioned in this file:&lt;br /&gt;
&lt;br /&gt;
*$user    Object that contains the characteristics of the user + his permissions.&lt;br /&gt;
*$conf    Object that contains Dolibarr configuration.&lt;br /&gt;
*$db      Object that contains an opened connection handler to the database.&lt;br /&gt;
*$langs   Object that contains the user&#039;s language.&lt;br /&gt;
&lt;br /&gt;
Then enter your code to display the page.&lt;br /&gt;
&lt;br /&gt;
*To include a class or library dedicated to the module is done using a Dolibarr function (and not using directly include_once):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
dol_include_once(&#039;/mymodule/class/myclass.class.php&#039;, &#039;MyClass&#039;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*To include classes provided with Dolibarr, use the following syntax:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
require_once DOL_DOCUMENT_ROOT.&#039;/core/class/doli.class.php&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Add some fields into existing forms===&lt;br /&gt;
You may want to provide a module that adds more fields into forms (input and view) of some elements. &lt;br /&gt;
&lt;br /&gt;
A heavy solution (but not so bad) may be to replace all pages used to create element (this means to disable the &amp;quot;New element&amp;quot; menu entry and adding yours, and disable tab that shows element to replace with a tab that is your own full page (copied/pasted from original) to do same than original page but modified to add your fields and stored added data into your own table). Go to menu [[#Define your entries in the menu (optional)]] and [[#The tab management (optional)]] if this solution suits you (this solution is more powerful since you can change everything you want into the page). &lt;br /&gt;
&lt;br /&gt;
We will describe here another solution, that works only to &amp;quot;add fields&amp;quot; at end of existing fields, using the element &amp;quot;category&amp;quot; as an example but you can convert this tutorial for invoice, proposal ...&lt;br /&gt;
&lt;br /&gt;
*First thing is to add a table, owned by your module, to store the value of new fields. This table will have only one column called &amp;quot;rowid&amp;quot; (will contain the same value than field rowid of element table) + one column for each new field you want to add. Then create a class with CRUD (Create/Read/Update/Delete) methods for this new table. For this two tasks, go back to previous chapter [[#Create your SQL tables and the PHP DAO class]].&lt;br /&gt;
*Next step is to add a hook into your module to add the new fields into the form. See chapter [[Hooks_system#Implement_the_Hook]] for generic documentation to use hooks.&lt;br /&gt;
&lt;br /&gt;
If you follow this tutorial, to be able to add fields into category forms, you must do:&lt;br /&gt;
{{ToComplete}}&lt;br /&gt;
&lt;br /&gt;
===Replace parts of screen that are templated (version 3.3+)===&lt;br /&gt;
Some parts of Dolibarr screen are isolated into native PHP template files.&lt;br /&gt;
You can develop a module to overwrite such templates with yours.&lt;br /&gt;
{{ToComplete}}&lt;br /&gt;
&lt;br /&gt;
===Add/replace part of fields supported by hooks===&lt;br /&gt;
See chapter [[Hooks_system#Implement_the_Hook]] to know how to use Dolibarr existing hooks to add/replace code at Dolibarr hooks place.&lt;br /&gt;
&lt;br /&gt;
===Database access===&lt;br /&gt;
If you need to edit some data in the database inside your own table, use the PHP class generated before.&lt;br /&gt;
&lt;br /&gt;
If you to make access to tables with no dedicated PHP class available, this is always possible (for example if you want to get a list of records with a particular join or filter). In this case, this is a code samples to follow:&lt;br /&gt;
&lt;br /&gt;
To make an insert, update or delete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$db-&amp;gt;begin();   // Start transaction&lt;br /&gt;
$db-&amp;gt;query(&amp;quot;My SQL request insert, update or delete&amp;quot;);&lt;br /&gt;
$db-&amp;gt;commit();       // Validate transaction&lt;br /&gt;
or $db-&amp;gt;rollback()  // Cancel transaction&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To read:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$resql=$db-&amp;gt;query(&amp;quot;My select request&amp;quot;);&lt;br /&gt;
if ($resql)&lt;br /&gt;
{&lt;br /&gt;
	$num = $db-&amp;gt;num_rows($resql);&lt;br /&gt;
	$i = 0;&lt;br /&gt;
	if ($num)&lt;br /&gt;
	{&lt;br /&gt;
		while ($i &amp;lt; $num)&lt;br /&gt;
		{&lt;br /&gt;
			$obj = $db-&amp;gt;fetch_object($resql);&lt;br /&gt;
			if ($obj)&lt;br /&gt;
			{&lt;br /&gt;
				// You can use here results&lt;br /&gt;
				print $obj-&amp;gt;field1;&lt;br /&gt;
				print $obj-&amp;gt;field2;&lt;br /&gt;
			}&lt;br /&gt;
			$i++;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Define style of your pages===&lt;br /&gt;
To have the look of your own pages to match the Dolibarr theme, it is necessary to use the Dolibarr CSS styles.&lt;br /&gt;
&lt;br /&gt;
You can use for example:&lt;br /&gt;
&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;liste_titre&#039;&#039;&#039;&amp;quot; on tags &#039;&#039;tr&#039;&#039; and &#039;&#039;td&#039;&#039; for the head row of a table.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;pair&#039;&#039;&#039;&amp;quot; or class=&amp;quot;&#039;&#039;&#039;impair&#039;&#039;&#039;&amp;quot; on tags &#039;&#039;tr&#039;&#039; and &#039;&#039;td&#039;&#039; of other rows of a table.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;flat&#039;&#039;&#039;&amp;quot; on all input fields (&#039;&#039;input, select, textarea&#039;&#039;...).&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;button&#039;&#039;&#039;&amp;quot; on HTML fields with type &#039;&#039;input type=&amp;quot;submit&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Use the Dolibarr date picker===&lt;br /&gt;
If you want to use the Dolibarr date selector (with its calendar popup) into your pages, use the following line:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $form=new Form($db);&lt;br /&gt;
 $form-&amp;gt;select_date(&#039;&#039;,&#039;mykey&#039;,0,0,0,&amp;quot;myform&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The string mykey will identify the date selector in the form. You must use different values if you use several date selectors in same page.&lt;br /&gt;
The string myform is the name of the FORM in which the selector is included (value found in the form name=&amp;quot;myform&amp;quot; in HTML page).&lt;br /&gt;
This means a date selector must be included necessarily into an html FORM.&lt;br /&gt;
&lt;br /&gt;
To get value after the POST of your form, the command is:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mydate = dol_mktime(12, 0 , 0, $_POST[&#039;mykeymonth&#039;], $_POST[&#039;mykeyday&#039;], $_POST[&#039;mykeyyear&#039;]);&lt;br /&gt;
print strftime(&#039;%A %d %B %Y&#039;, $mydate);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Add your own setup page (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs parameters, which are to be provided by the user, for proper setting up of the module.&lt;br /&gt;
&lt;br /&gt;
===Create your page to edit parameters===&lt;br /&gt;
If your module needs several parameters to be setup, you must create a page to edit options (these options will be saved in the [[Table llx_const|table &#039;&#039;&#039;llx_const&#039;&#039;&#039;]]).&lt;br /&gt;
Create a page named &#039;&#039;&#039;mymodule_setuppage.php&#039;&#039;&#039; that shows a form for possible options to update them into the above-mentioned table.&lt;br /&gt;
It is necessary to take an example from a page of the directory &#039;&#039;&#039;/admin&#039;&#039;&#039; that will show you the way to read/save your parameters.&lt;br /&gt;
Put this PHP page into the directory &#039;&#039;&#039;/admin&#039;&#039;&#039; of your module (e.g. mymodule/admin/mymodule_setuppage.php).&lt;br /&gt;
&lt;br /&gt;
===Modify the descriptor file of your module===&lt;br /&gt;
Then, within the descriptor file of your module, modify the variable &#039;&#039;&#039;config_page_url&#039;&#039;&#039; to set the name of this PHP page.&lt;br /&gt;
If the page is in the directory &#039;&#039;&#039;admin/&#039;&#039;&#039;, then the path is not required, e.g. like this:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;mymodule_setuppage.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the page is in the directory &#039;&#039;&#039;mymodule/admin/&#039;&#039;&#039;, then like this:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;mymodule_setuppage.php@mymodule&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Test your page===&lt;br /&gt;
Go into page &#039;&#039;&#039;Home-&amp;gt;Setup-&amp;gt;Modules&#039;&#039;&#039;, you should see a picture at the end of the line of your module to reach your setup page. Click on it, you should be able to view/edit parameters from your page.&lt;br /&gt;
&lt;br /&gt;
==Define your entries in menu (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you have created PHP pages, it is necessary that those pages can be reached from menu entries in Dolibarr menu.&lt;br /&gt;
&lt;br /&gt;
===Define your menu entries===&lt;br /&gt;
For this, you must define into the module descriptor, the array this-&amp;gt;menu that declares all menus added by your module.&lt;br /&gt;
This array contains entries that will appear once your module is activated.&lt;br /&gt;
The example module descriptor file &#039;&#039;&#039;modMyModule.class.php&#039;&#039;&#039; contains an example to declare a top menu and also its left menu entries.&lt;br /&gt;
&lt;br /&gt;
This is the example of code to declare your own menu entries in a module descriptor file:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Main menu entries&lt;br /&gt;
$this-&amp;gt;menu = array();			// List of menus to add&lt;br /&gt;
$r=0;&lt;br /&gt;
&lt;br /&gt;
// Add here entries to declare new menus&lt;br /&gt;
// Example to declare the Top Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;0,			// Put 0 if this is a top menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;top&#039;,			// This is a Top menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MyModule top menu&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;mymodule&#039;,&lt;br /&gt;
			&#039;leftmenu&#039;=&amp;gt;&#039;mymodule&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/mymodule/pagetop.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;mymodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users, 1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&lt;br /&gt;
// Example to declare a Left Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;&#039;fk_mainmenu=xxx&#039;,		    // Use &#039;fk_mainmenu=xxx&#039; or &#039;fk_mainmenu=xxx,fk_leftmenu=yyy&#039; where xxx is mainmenucode and yyy is a leftmenucode of parent menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;left&#039;,			        // This is a Left menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MyModule left menu 1&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;xxx&#039;,&lt;br /&gt;
                        &#039;leftmenu&#039;=&amp;gt;&#039;yyy&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/mymodule/pagelevel1.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;mymodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users,1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To show the menu or not depending on a permission, modify property &#039;&#039;&#039;perms&#039;&#039;&#039; in the array. See chapter on permissions later to see how to add permissions.&lt;br /&gt;
&lt;br /&gt;
===Test your menu entries===&lt;br /&gt;
Disable and re-enable your module under the Dolibarr module setup page, menus entries must appear (if property &#039;enabled&#039; is declaration array is ok).&lt;br /&gt;
&lt;br /&gt;
==Add your own permissions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you want to add new permissions.&lt;br /&gt;
&lt;br /&gt;
The way to define permissions that will manage your module is done inside the module descriptor created previously.&lt;br /&gt;
Modify line &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights_class = &#039;mymodule&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
with correct value for mymodule.&lt;br /&gt;
&lt;br /&gt;
Then you must fill the array $this-&amp;gt;rights with as many entries than different permissions you need to manage.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights[$r][0] = 10001;&lt;br /&gt;
$this-&amp;gt;rights[$r][1] = &#039;Label by default of permission&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][3] = 1;&lt;br /&gt;
$this-&amp;gt;rights[$r][4] = &#039;action&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][5] = &#039;subaction&#039;;&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Into $this-&amp;gt;rights[$r][0], put a permission id not already used (See into menu &#039;&#039;&#039;System info&#039;&#039;&#039; on a working installation of Dolibarr to know list of id already used by standard modules.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][3], put 1 if this permission must be granted automatically by default to any newly created user.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][1], put a label by default for permission (This label will be used if no translation can be found into the file &#039;&#039;&#039;admin.lang&#039;&#039;&#039; Translation key should be &amp;quot;Permission10001=My permission Label&amp;quot;).&lt;br /&gt;
Into $this-&amp;gt;rights[$r][4] and $this-&amp;gt;rights[$r][5], put an action and subaction string without spaces. You will be able to test if a user has the permission in your PHP source code with the sequence:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;action-&amp;gt;subaction) ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Define your own box (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs to provide one or several new boxes to show on home page.&lt;br /&gt;
&lt;br /&gt;
===Define your box===&lt;br /&gt;
For this, modify the array $this-&amp;gt;boxes into the module descriptor file.&lt;br /&gt;
All you have to do is to add 2 lines for each box file you will create into directory &#039;&#039;&#039;htdocs/mymodule/core/boxes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example:&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;file&#039;]=&#039;mybox0.php@mymodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;note&#039;]=&#039;My box 0&#039;&lt;br /&gt;
 ...&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;file&#039;]=&#039;myboxn.php@mymodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;note&#039;]=&#039;My box n&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then create files &#039;&#039;&#039;htdocs/mymodule/core/boxes/mybox0.php&#039;&#039;&#039;, &#039;&#039;&#039;htdocs/mymodule/core/boxes/mybox1.php&#039;&#039;&#039;... by copying an example from an existing box file (found into directory &#039;&#039;&#039;htdocs/core/boxes&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
===Test if your box is detected by Dolibarr===&lt;br /&gt;
Disable and enabled module.&lt;br /&gt;
&lt;br /&gt;
Go into menu &#039;&#039;&#039;Home - Setup - Boxes&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Your boxes must appear in the list of boxes you can activate. Activate the box and go on the home page to see if the box is showing correctly.&lt;br /&gt;
&lt;br /&gt;
==Define your own export (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module provides new predefined database export profiles (for its own tables or for already existing tables of another module).&lt;br /&gt;
&lt;br /&gt;
===Define export===&lt;br /&gt;
For this uncomment and modify arrays $this-&amp;gt;export_xxx in your module descriptor file.&lt;br /&gt;
&lt;br /&gt;
===Test your export===&lt;br /&gt;
Go into menu Tools -&amp;gt; Export. Your export will appear in the list of available predefined exports (if your module is enabled).&lt;br /&gt;
Choose it, you must see a list of all possible fields defined in the export arrays.&lt;br /&gt;
Choose on field and try to build an export file. If ok, try again with all fields.&lt;br /&gt;
&lt;br /&gt;
==Define your CSS styles (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If in your PHP pages, you use class styles that are not defined inside Dolibarr themes CSS (not recommanded).&lt;br /&gt;
&lt;br /&gt;
===Create and declare your style sheet===&lt;br /&gt;
Create a style sheet CSS named &#039;&#039;&#039;mymodule.css&#039;&#039;&#039; or &#039;&#039;&#039;mymodule.css.php&#039;&#039;&#039; and put it into directory &#039;&#039;&#039;htdocs/mymodule&#039;&#039;&#039;. You can have several CSS files per module.&lt;br /&gt;
Remember it&#039;s better to use existing styles already available by default into Dolibarr (The CSS file used by Dolibarr is file &#039;&#039;&#039;themes/mytheme/&#039;&#039;themename&#039;&#039;.css.php&#039;&#039;&#039;. Create your own CSS files only if you need absolutely to add not already existing styles.&lt;br /&gt;
&lt;br /&gt;
Once your style sheets are ready, declare them into your module descriptor file by modifying the property &#039;&#039;&#039;$this-&amp;gt;modules_parts&#039;&#039;&#039;.&lt;br /&gt;
Value to put here must be an array of relative URLs to your CSS files.&lt;br /&gt;
For example&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;module_parts = array(&#039;css&#039; =&amp;gt; array(&#039;/mymodule/css/mymodule.css.php&#039;,&#039;/mymodule/css/myother.css&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Test your style sheet===&lt;br /&gt;
Disable and enable your module.&lt;br /&gt;
&lt;br /&gt;
Go on the home page (index.php). Show the HTML source of the page.&lt;br /&gt;
&lt;br /&gt;
You should see into the HTML header, a line that declares your style sheet.&lt;br /&gt;
&lt;br /&gt;
==Add your Javascript functions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If in your PHP pages, you use javascript functions not available in Dolibarr (in file lib_head.js)&lt;br /&gt;
&lt;br /&gt;
If you need to use your own javascript functions inside your PHP pages, it is necessary to have your functions, defined into your javascript file &#039;&#039;&#039;htdocs/mymodule/js/mymodule.js&#039;&#039;&#039;, included into the HTML HEAD section.&lt;br /&gt;
To ask Dolibarr that forge this header to include your own javascript file, you must just provide it to the llxHeader() function called by your page.&lt;br /&gt;
&lt;br /&gt;
Example for page /htdocs/mymodule/mypage.php :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$morejs=array(&amp;quot;/mymodule/js/mymodule.js&amp;quot;);&lt;br /&gt;
llxHeader(&#039;&#039;,&#039;Titre&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,$morejs,&#039;&#039;,0,0); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Run your own code on any Dolibarr event (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you want to execute your own code once a common Dolibarr event has occurred (example: I want to update a table in my module when an invoice is created into Dolibarr), you must create a &#039;&#039;&#039;triggers&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
See also [[Interfaces_Dolibarr_toward_foreign_systems]]&lt;br /&gt;
and [[Interfaces_from_foreign_systems_toward_Dolibarr]]&lt;br /&gt;
&lt;br /&gt;
==Insert your code inside Dolibarr hooks positions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to add code or replace Dolibarr code into another situation than a business event (See the previous chapter for adding code during a business event).&lt;br /&gt;
&lt;br /&gt;
See page [[Hooks_system]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Add your own numbering rules==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you need a new rule for generated ref of elements that are not covered by existing rules.&lt;br /&gt;
&lt;br /&gt;
See page [[Create numbering module]].&lt;br /&gt;
&lt;br /&gt;
==Add your document template (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to personalized your own generated PDF or ODT documents.&lt;br /&gt;
&lt;br /&gt;
Note: To add this feature you don&#039;t need to create a module descriptor.&lt;br /&gt;
&lt;br /&gt;
Documentation to add your own template is available on page [[Create_a_PDF_document_template]] or [[Create_an_ODT_document_template]].&lt;br /&gt;
&lt;br /&gt;
==Add your skin (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to personalized your colors/fonts/images.&lt;br /&gt;
&lt;br /&gt;
Note: To add this feature you don&#039;t need to create a module descriptor.&lt;br /&gt;
&lt;br /&gt;
To add your own skin, read page [[Skins]].&lt;br /&gt;
&lt;br /&gt;
=Some coding rules and predefined functions=&lt;br /&gt;
The coding rules to be followed are defined in the [[Developer documentation]], under section &amp;quot;General Information - Language and standards development&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A lot of predefined features for developers are also available and described into page [[Developer documentation]] under section &amp;quot;Technical components of Dolibarr&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=Create a package to distribute and install your module=&lt;br /&gt;
This process must be used to generate a package to submit it on the http://www.dolistore.com marketplace.&lt;br /&gt;
But you can use it to have a package easy to distribute on your own network.&lt;br /&gt;
&lt;br /&gt;
*Go into the directory &#039;&#039;&#039;/build&#039;&#039;&#039; and copy the file &#039;&#039;&#039;makepack-dolibarrmodules.conf&#039;&#039;&#039; into &#039;&#039;&#039;makepack-mymodule.conf&#039;&#039;&#039;. Warning, this directory may not be provided in some packages of stable versions. If so, it can be retrieved from the snapshot available for download on the Dolibarr website in area &amp;quot;Development version&amp;quot; (taken in this case the whole build directory which is autonomous and independent directory).&lt;br /&gt;
&lt;br /&gt;
Edit this file to add a list of file names for all new files you created for your module (module descriptor, new sql tables files, php page, images, etc...)&lt;br /&gt;
&lt;br /&gt;
*Run the script via Perl (need the Perl version 5.0 or later):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
perl makepack-dolibarrmodule.pl&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The script asks you the name of your module, its major and minor version. A file &#039;&#039;&#039;mymodule.zip &#039;&#039;&#039; will then be manufactured containing your module ready to be deployed.&lt;br /&gt;
&lt;br /&gt;
*The person who receives your module must then place the file in the root directory of a Dolibarr installation and perform the command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tar -xvf mymodule.zip&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*If you want your module to be public, you can submit it (the zip file) on Dolibarr marketplace website: {{LinkToPluginDownload}} (you must create an account first and be logged to use the link &amp;quot;Submit a module/product&amp;quot;).&lt;br /&gt;
**If your module was built correctly, the file will be validated later.&lt;br /&gt;
**If quality is enough and license permits it, the code might be added inside main Dolibarr sources (except if you disagree for that).&lt;br /&gt;
&lt;br /&gt;
=Enabling/activation condition of external module on DoliStore=&lt;br /&gt;
&lt;br /&gt;
See [[Module_Dolistore_Validation_Rules|Validation Rules]]&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>ALSOFT</name></author>
	</entry>
	<entry>
		<id>https://wiki.dolibarr.org/index.php?title=Module_development&amp;diff=49920</id>
		<title>Module development</title>
		<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php?title=Module_development&amp;diff=49920"/>
		<updated>2021-03-09T07:18:20Z</updated>

		<summary type="html">&lt;p&gt;ALSOFT: /* Create a new PHP screen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- BEGIN origin interlang links --&amp;gt;&lt;br /&gt;
&amp;lt;!-- You can edit this section but do NOT remove these comments&lt;br /&gt;
     Links below will be automatically replicated on translated pages by PolyglotBot --&amp;gt;&lt;br /&gt;
[[fr:Développement_module]]&lt;br /&gt;
[[es:Desarrollo_de_un_módulo]]&lt;br /&gt;
[[de:Modul_Entwicklung]]&lt;br /&gt;
[[zh:模块开发]]&lt;br /&gt;
&amp;lt;!-- END interlang links --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
{{TemplateDocDevEn}}&lt;br /&gt;
&lt;br /&gt;
To create a new module/addon for Dolibarr, there is several steps. This tutorial will describe you each of them to build a module to extend Dolibarr features, like one or several of the following :&lt;br /&gt;
&lt;br /&gt;
*Add new tables in database&lt;br /&gt;
*Add your own menu entries&lt;br /&gt;
*Add new screens to edit new tables&lt;br /&gt;
*Add or remove tabs on object view (invoice, product, order, event, ...)&lt;br /&gt;
*Add predefined exports for the internal export tool&lt;br /&gt;
*Add new information boxes in the home page&lt;br /&gt;
*Add new substitutions variables&lt;br /&gt;
*Define new permissions&lt;br /&gt;
*Execute code automatically triggered by a particular Dolibarr action&lt;br /&gt;
*Insert your code inside Dolibarr hooks positions&lt;br /&gt;
*Add your numbering module&lt;br /&gt;
*Add a new document template&lt;br /&gt;
*Add a new skin&lt;br /&gt;
&lt;br /&gt;
etc...&lt;br /&gt;
&lt;br /&gt;
Following chapters presents how to do all of this manually with an easy way.&lt;br /&gt;
&lt;br /&gt;
=Module creation with the module builder=&lt;br /&gt;
From Dolibarr 9.0 it is possible to create the main pages of your module with the Module Builder. To activate it, go into the list of module and enable the module &amp;quot;Module Builder&amp;quot;, then click on the &amp;quot;bug&amp;quot; image in the top right of screen.&lt;br /&gt;
&lt;br /&gt;
=Example of Template External Module=&lt;br /&gt;
A good model to start development of external module can be found here : [https://github.com/Dolibarr/dolibarr/tree/develop/htdocs/modulebuilder/template GitHub Dolibarr Module Modèle]&lt;br /&gt;
&lt;br /&gt;
=Create your module=&lt;br /&gt;
==Create a Module descriptor for your Module (required)==&lt;br /&gt;
&#039;&#039;&#039;When it is required&#039;&#039;&#039;: Required as soon as an addon is developed, whatever its goal is (except for adding a skin).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since Dolibarr 9.0, you should use the ModuleBuilder module provided as a standard module to generate the module descriptor&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Create your module descriptor===&lt;br /&gt;
The first step is to create a file descriptor for the module. &lt;br /&gt;
&lt;br /&gt;
*Create directory &#039;&#039;&#039;/htdocs/&#039;&#039;mymodule&#039;&#039;/core/modules&#039;&#039;&#039;. Then copy the file modMyModule.class.php from the directory dev/skeletons into this directory &#039;&#039;&#039;htdocs/&#039;&#039;mymodule&#039;&#039;/core/modules&#039;&#039;&#039;. Change the name of the file modMyModule.class.php to the name corresponding to the purpose of your module. Name of the file must start with initial &#039;mod&#039; and end with .class.php (for example if you want to give the name &#039;NewName&#039; to this file, then the name should be &#039;modNewName.class.php&#039;).&lt;br /&gt;
&lt;br /&gt;
Next modify the contents of this file as follows:&lt;br /&gt;
&lt;br /&gt;
*Replace all &amp;quot;modMyModule&amp;quot; with a value which corresponds to the purpose of your module. This value must always start with &#039;mod&#039; and contain only alpha characters (again, if the name given to the file was &#039;NewName&#039;, then replace all &amp;quot;modMyModule&amp;quot; with &amp;quot;modNewName&amp;quot;).&lt;br /&gt;
*Change the number in: $this-&amp;gt;numero = 100000 by a number that designates your module id. To avoid conflicts with other modules, you can consult the page that lists already reserved id numbers: [[List of modules id|List of modules id]].&lt;br /&gt;
*Modify any other variables defined in the constructor (see comment in the code skeleton for their meaning).&lt;br /&gt;
&lt;br /&gt;
Your file descriptor for your module is ready. See the next step to activate it.&lt;br /&gt;
&lt;br /&gt;
===Test your descriptor===&lt;br /&gt;
&lt;br /&gt;
Launch Dolibarr and go to page &#039;&#039;&#039;Setup-&amp;gt;module&#039;&#039;&#039;? &lt;br /&gt;
If you set the property version in the module description you should see a new line with your new module and the possibility to activate it or not. If you set the property version to &amp;quot;develop&amp;quot; or &amp;quot;experiental&amp;quot;, to see your module, you must first go into &#039;&#039;&#039;Setup-Others&#039;&#039;&#039; and set MAIN_FEATURES_LEVEL to 1 to see &amp;quot;experimental&amp;quot; modules or 2 to see &amp;quot;development&amp;quot; modules.&lt;br /&gt;
&lt;br /&gt;
==Tree of path for new module files (required)==&lt;br /&gt;
This is how your files must be organized when building a new module (the zip file must also match this rule).&lt;br /&gt;
Note: Only the second line is mandatory.&lt;br /&gt;
&lt;br /&gt;
{{TemplateModuleTreeSimple}}&lt;br /&gt;
&lt;br /&gt;
==Create your SQL tables and the PHP DAO class (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs to manage data of its own&lt;br /&gt;
&lt;br /&gt;
===Create your .sql file===&lt;br /&gt;
If your module is designed to manage data of its own, which are not available in the standard version of Dolibarr, it is necessary to define SQL tables to store the data.&lt;br /&gt;
&lt;br /&gt;
Scripts for creating tables and load data by your own module are saved into a subdirectory called &amp;quot;/mymodule/sql&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Then check into your descriptor file, into function &#039;&#039;&#039;init&#039;&#039;&#039; that the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;$this-&amp;gt;_load_tables(&#039;/mymodule/sql/&#039;);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
is not commented.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Rules to follow:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Add the files about creating tables commands on the principle of a file &#039;&#039;&#039;llx_matable.sql&#039;&#039;&#039; per table, with a possibly file &#039;&#039;&#039;llx_matable.key.sql&#039;&#039;&#039; (see existing files in &#039;&#039;&#039;install/mysql/tables&#039;&#039;&#039; for examples).&lt;br /&gt;
*The recommended type and name for SQL fields are defined into page [[Language_and_development_rules#Table_and_fields_structures]].&lt;br /&gt;
*To manage data, you must create a file called &#039;&#039;&#039;data.sql&#039;&#039;&#039; inside directory &#039;&#039;&#039;/mymodule/sql/&#039;&#039;&#039; that contains SQL command to add/edit/delete data.&lt;br /&gt;
*Don&#039;t use the double quote for strings (eg &#039;chaine&#039; not &amp;quot;chaine&amp;quot;) because the double quote have a specific meaning in PostGreSQL&lt;br /&gt;
&lt;br /&gt;
Example of content of a file data.sql&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
 delete from llx_const where name=&#039;MYMODULE_IT_WORKS&#039; and entity=&#039;__ENTITY__&#039;;&lt;br /&gt;
 insert into llx_const (name, value, type, note, visible, entity) values (&#039;MYMODULE_IT_WORKS&#039;,&#039;1&#039;,&#039;chaine&#039;,&#039;A constant vor my module&#039;,1,&#039;__ENTITY__&#039;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Files must be operational for the database mysql. Rem: The files of other databases are not maintained. They will be read and converted on the fly by the driver of the other database.&lt;br /&gt;
&lt;br /&gt;
===Test your .sql files===&lt;br /&gt;
&lt;br /&gt;
Once the files ready, you can return to Dolibarr to disable the module, drop those tables in the database and reactivate the module. The tables should be recreated by the activation of the module. If this is not the case, check your scripts by passing them by hand, or check the Dolibarr logs.&lt;br /&gt;
&lt;br /&gt;
===Generate the PHP DAO class===&lt;br /&gt;
Once you have created your tables into the database, move to the dev/skeletons directory and run the script&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;php build_class_from_table.php tablename modulename&amp;lt;/source&amp;gt;&lt;br /&gt;
Note: If the command does not work, try to use php-cli php instead.&lt;br /&gt;
&lt;br /&gt;
This will generate a file &#039;&#039;&#039;out.tablename.class.php&#039;&#039;&#039; that contains the class to manage table tablename. &lt;br /&gt;
In this class, you can find the CRUD methods (Create / Read / Update / Delete) already working to do an insert, a fetch (select), an update, a delete of a row in table.&lt;br /&gt;
Remove just the &amp;quot;out&amp;quot; from the file name and put the file in a subdirectory of &#039;&#039;&#039;htdocs&#039;&#039;&#039; specific to your module (in htdocs/mymodule for example).&lt;br /&gt;
&lt;br /&gt;
A file &#039;&#039;&#039;out.tablename_script.php&#039;&#039;&#039; has been generated and contains a sample code to use the class for each of the 4 CRUD methods.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since Dolibarr 6.0, the file dev/skeletons/build_class_from_table.php is no more provided. To build a class from a table you should use the ModuleBuilder modules provided as a standard module.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==The tab management (optional)==&lt;br /&gt;
&lt;br /&gt;
===Add or remove your own tabs on object sheets===&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: To add a tab on an object (invoices, orders, proposals, member ...)&lt;br /&gt;
&lt;br /&gt;
To do this go into the file descriptor of module previously created and edit the $this-&amp;gt;tabs array:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	// Array to add new pages in new tabs or remove existing one&lt;br /&gt;
	$this-&amp;gt;tabs = array(&#039;objecttype:+tabname1:Title1:mylangfile@mymodule:$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read:/mymodule/mypagetab1.php?id=__ID__&#039;    // To add a new tab identified by code tabname1&lt;br /&gt;
                            &#039;objecttype:+tabname2:Title2:mylangfile@mymodule:$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read:/mymodule/mypagetab2.php?id=__ID__&#039;,   // To add a new tab identified by code tabname2&lt;br /&gt;
                            &#039;objecttype:-tabname&#039;);                                                     // To remove an existing tab identified by code tabname&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The table should contain a list of strings, each string representing a new tab. &lt;br /&gt;
The format of the string consisting of 5 parts separated by &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
*Part 1: The element type (object type) where the tab should appear is a value from the following:&lt;br /&gt;
{{TemplateModuleTabs}}&lt;br /&gt;
&lt;br /&gt;
*Part 2: A code to identify tab to add (start with +) or to remove (start with -)&lt;br /&gt;
*Part 3: The title of the tab. This can be a hard read or better code translation in a file lang.&lt;br /&gt;
*Part 4: The name of the file &amp;quot;*.lang&amp;quot; which contains correspondence between the code translation and language to display. If this name is followed with @mymodule, Dolibarr will search translation file &amp;quot;*.lang&amp;quot; within the module, so htdocs/mymodule/langs/code_CODE/mylangfile.lang, otherwise Dolibarr will look for file htdocs/langs/code_CODE/mylangfile.lang&lt;br /&gt;
*Part 5: A condition to test if tab must be visible. Put 1 to be always visible.&lt;br /&gt;
*Part 6: The URL of the page to display when you click on the tab. The __ID__ string will be replaced automatically by the Id of the element concerned.&lt;br /&gt;
&lt;br /&gt;
To feed the contents of the tab with data from the database, see the next chapter.&lt;br /&gt;
&lt;br /&gt;
In order to get the names  &#039;tabname&#039; of existing tabs, you have to check the names used in the function &#039;product_prepare_head&#039; of the file  &#039;core/lib/module.lib.php&#039; corresponding to section &#039;$head[$h][2]&#039;.&lt;br /&gt;
&lt;br /&gt;
===Show tabs navigation into your own pages===&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: To show all standard tabs of an object (product, tiers, etc.) on your page.&lt;br /&gt;
&lt;br /&gt;
You must follow these steps :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Include files you need into your file&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For each object type, there are two files to include with line&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;require_once($url_fichier) ;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is example of files to include (DOL_DOCUMENT_ROOT is often dolibarr/htdocs/) :&lt;br /&gt;
&lt;br /&gt;
*Object thirdparty (thirdparty) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/societe/class/societe.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/company.lib.php&lt;br /&gt;
*Object product (product) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/product/class/product.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/product.lib.php&lt;br /&gt;
*Object invoice (invoice) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/compta/facture/class/facture.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/invoice.lib.php&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Create and load the object to show into your tab&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create an instance of an object of the correct class and load object from the database by using the fetch method of an object in providing to this method the id you get from URL (ie : /mytab.php?id=1).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$id=GETPOST(&#039;id&#039;,&#039;int&#039;);&lt;br /&gt;
$ref=GETPOST(&#039;ref&#039;,&#039;alpha&#039;);&lt;br /&gt;
$product = new Product($db) ;&lt;br /&gt;
$result = $product-&amp;gt;fetch($id,$ref) ; // Test $result to check the database read is ok&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Get a list of all tabs to show for your object type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Use function XXX_prepare_head($obj), where XXX is name of object. This will return an array with all definition of tab entries to show. The parameter to put into this method is the instance of an object you want tabs.&lt;br /&gt;
&lt;br /&gt;
The resulting array has the following structure&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$head        // Array of tabs&lt;br /&gt;
$head[$h]    // Element to describe one tab.&lt;br /&gt;
$head[$h][0] // Url of page to show when you click on tab&lt;br /&gt;
$head[$h][1] // Title of tab&lt;br /&gt;
$head[$h][2] // Code name to identify the tab&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$head = product_prepare_head($product, $user) ; // parameter $user is present for some function anly&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. show tabs into your page&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Use function dol_fiche_head() to show all tabs defined into array $head returned by XX_prepare_head().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
dol_fiche_head($links, $active=&#039;0&#039;, $title=&#039;&#039;, $notab=0, $picto=&#039;&#039;)&lt;br /&gt;
//$links  // Tableau des onglets, appelé $head plus haut.&lt;br /&gt;
//$active // Onglet actif (mettre le nom de l&#039;onglet défini dans votre fichier de module, ou un nom contenu dans $head[$h][2]). Cet onglet sera mis en surbrillance&lt;br /&gt;
//$title  // Title to show (shown into a special tab that you can&#039;t click)&lt;br /&gt;
//$notab&lt;br /&gt;
//$picto  // Name of image to show into title. Possible values are:&lt;br /&gt;
//            product&lt;br /&gt;
//            service&lt;br /&gt;
//            company&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will show required tabs and open an html element &#039;&#039;&amp;lt; div class=&amp;quot;&amp;quot; &amp;gt;&#039;&#039; that correspond to the area under the tabs. To close area of a tab, just use &#039;&#039;&amp;lt; /div &amp;gt;&#039;&#039; into your PHP page.&lt;br /&gt;
&lt;br /&gt;
==Create or modify PHP screens (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If the purpose of your module is to add features that require new or modified screens.&lt;br /&gt;
&lt;br /&gt;
===Create a new PHP screen===&lt;br /&gt;
You must then create your PHP pages that will show/edit data from tables using the skeleton templates provided as an example in the directory &#039;&#039;&#039;modulebuilder/myobject_page.php&#039;&#039;&#039; (For the development of a script from the command line, see [[Script development]]).&lt;br /&gt;
&lt;br /&gt;
To create a new user screen, create a subdirectory of &#039;&#039;&#039;htdocs&#039;&#039;&#039; (if not already done) for your module (in &#039;&#039;&#039;htdocs/mymodule&#039;&#039;&#039; for example) to store the pages you will create.&lt;br /&gt;
&lt;br /&gt;
Copy, into that directory, the file &#039;&#039;&#039;myobject_page.phpp&#039;&#039;&#039; that will serve as a starting point for your page file.&lt;br /&gt;
Edit the file to have a correct relative path to the main.inc.php file. &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Load Dolibarr environment&lt;br /&gt;
$res=0;&lt;br /&gt;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; ! empty($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;])) $res=@include($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;].&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME&lt;br /&gt;
$tmp=empty($_SERVER[&#039;SCRIPT_FILENAME&#039;])?&#039;&#039;:$_SERVER[&#039;SCRIPT_FILENAME&#039;];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1;&lt;br /&gt;
while($i &amp;gt; 0 &amp;amp;&amp;amp; $j &amp;gt; 0 &amp;amp;&amp;amp; isset($tmp[$i]) &amp;amp;&amp;amp; isset($tmp2[$j]) &amp;amp;&amp;amp; $tmp[$i]==$tmp2[$j]) { $i--; $j--; }&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php using relative path&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res) die(&amp;quot;Include of main fails&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
As you can see, there is several tries to load the main.inc.php (or master.inc.php). The goal is to succeed in the most cases as possible. The minimum is 2 lines: one to try to load the master/main.inc.php into the dolibarr root directory and another one to try to load the file to support the case when the module is deployed into the &amp;quot;custom&amp;quot; directory. But you can have more to deal more situation. The provided example should be able to load the file main/master.inc.php in nearly all situation/setups.&lt;br /&gt;
&lt;br /&gt;
Note that you may add more &amp;quot;../&amp;quot; depending on the depth of the file relative to your module directory tree.&lt;br /&gt;
&lt;br /&gt;
It&#039;s in the main.inc.php file that is loaded technical environment variables and permissions. The following variables are objects positioned in this file:&lt;br /&gt;
&lt;br /&gt;
*$user    Object that contains the characteristics of the user + his permissions.&lt;br /&gt;
*$conf    Object that contains Dolibarr configuration.&lt;br /&gt;
*$db      Object that contains an opened connection handler to the database.&lt;br /&gt;
*$langs   Object that contains the user&#039;s language.&lt;br /&gt;
&lt;br /&gt;
Then enter your code to display the page.&lt;br /&gt;
&lt;br /&gt;
*To include a class or library dedicated to the module is done using a Dolibarr function (and not using directly include_once):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
dol_include_once(&#039;/mymodule/class/myclass.class.php&#039;, &#039;MyClass&#039;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*To include classes provided with Dolibarr, use the following syntax:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
require_once DOL_DOCUMENT_ROOT.&#039;/core/class/doli.class.php&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Add some fields into existing forms===&lt;br /&gt;
You may want to provide a module that adds more fields into forms (input and view) of some elements. &lt;br /&gt;
&lt;br /&gt;
A heavy solution (but not so bad) may be to replace all pages used to create element (this means to disable the &amp;quot;New element&amp;quot; menu entry and adding yours, and disable tab that shows element to replace with a tab that is your own full page (copied/pasted from original) to do same than original page but modified to add your fields and stored added data into your own table). Go to menu [[#Define your entries in the menu (optional)]] and [[#The tab management (optional)]] if this solution suits you (this solution is more powerful since you can change everything you want into the page). &lt;br /&gt;
&lt;br /&gt;
We will describe here another solution, that works only to &amp;quot;add fields&amp;quot; at end of existing fields, using the element &amp;quot;category&amp;quot; as an example but you can convert this tutorial for invoice, proposal ...&lt;br /&gt;
&lt;br /&gt;
*First thing is to add a table, owned by your module, to store the value of new fields. This table will have only one column called &amp;quot;rowid&amp;quot; (will contain the same value than field rowid of element table) + one column for each new field you want to add. Then create a class with CRUD (Create/Read/Update/Delete) methods for this new table. For this two tasks, go back to previous chapter [[#Create your SQL tables and the PHP DAO class]].&lt;br /&gt;
*Next step is to add a hook into your module to add the new fields into the form. See chapter [[Hooks_system#Implement_the_Hook]] for generic documentation to use hooks.&lt;br /&gt;
&lt;br /&gt;
If you follow this tutorial, to be able to add fields into category forms, you must do:&lt;br /&gt;
{{ToComplete}}&lt;br /&gt;
&lt;br /&gt;
===Replace parts of screen that are templated (version 3.3+)===&lt;br /&gt;
Some parts of Dolibarr screen are isolated into native PHP template files.&lt;br /&gt;
You can develop a module to overwrite such templates with yours.&lt;br /&gt;
{{ToComplete}}&lt;br /&gt;
&lt;br /&gt;
===Add/replace part of fields supported by hooks===&lt;br /&gt;
See chapter [[Hooks_system#Implement_the_Hook]] to know how to use Dolibarr existing hooks to add/replace code at Dolibarr hooks place.&lt;br /&gt;
&lt;br /&gt;
===Database access===&lt;br /&gt;
If you need to edit some data in the database inside your own table, use the PHP class generated before.&lt;br /&gt;
&lt;br /&gt;
If you to make access to tables with no dedicated PHP class available, this is always possible (for example if you want to get a list of records with a particular join or filter). In this case, this is a code samples to follow:&lt;br /&gt;
&lt;br /&gt;
To make an insert, update or delete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$db-&amp;gt;begin();   // Start transaction&lt;br /&gt;
$db-&amp;gt;query(&amp;quot;My SQL request insert, update or delete&amp;quot;);&lt;br /&gt;
$db-&amp;gt;commit();       // Validate transaction&lt;br /&gt;
or $db-&amp;gt;rollback()  // Cancel transaction&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To read:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$resql=$db-&amp;gt;query(&amp;quot;My select request&amp;quot;);&lt;br /&gt;
if ($resql)&lt;br /&gt;
{&lt;br /&gt;
	$num = $db-&amp;gt;num_rows($resql);&lt;br /&gt;
	$i = 0;&lt;br /&gt;
	if ($num)&lt;br /&gt;
	{&lt;br /&gt;
		while ($i &amp;lt; $num)&lt;br /&gt;
		{&lt;br /&gt;
			$obj = $db-&amp;gt;fetch_object($resql);&lt;br /&gt;
			if ($obj)&lt;br /&gt;
			{&lt;br /&gt;
				// You can use here results&lt;br /&gt;
				print $obj-&amp;gt;field1;&lt;br /&gt;
				print $obj-&amp;gt;field2;&lt;br /&gt;
			}&lt;br /&gt;
			$i++;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Define style of your pages===&lt;br /&gt;
To have the look of your own pages to match the Dolibarr theme, it is necessary to use the Dolibarr CSS styles.&lt;br /&gt;
&lt;br /&gt;
You can use for example:&lt;br /&gt;
&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;liste_titre&#039;&#039;&#039;&amp;quot; on tags &#039;&#039;tr&#039;&#039; and &#039;&#039;td&#039;&#039; for the head row of a table.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;pair&#039;&#039;&#039;&amp;quot; or class=&amp;quot;&#039;&#039;&#039;impair&#039;&#039;&#039;&amp;quot; on tags &#039;&#039;tr&#039;&#039; and &#039;&#039;td&#039;&#039; of other rows of a table.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;flat&#039;&#039;&#039;&amp;quot; on all input fields (&#039;&#039;input, select, textarea&#039;&#039;...).&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;button&#039;&#039;&#039;&amp;quot; on HTML fields with type &#039;&#039;input type=&amp;quot;submit&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Use the Dolibarr date picker===&lt;br /&gt;
If you want to use the Dolibarr date selector (with its calendar popup) into your pages, use the following line:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $form=new Form($db);&lt;br /&gt;
 $form-&amp;gt;select_date(&#039;&#039;,&#039;mykey&#039;,0,0,0,&amp;quot;myform&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The string mykey will identify the date selector in the form. You must use different values if you use several date selectors in same page.&lt;br /&gt;
The string myform is the name of the FORM in which the selector is included (value found in the form name=&amp;quot;myform&amp;quot; in HTML page).&lt;br /&gt;
This means a date selector must be included necessarily into an html FORM.&lt;br /&gt;
&lt;br /&gt;
To get value after the POST of your form, the command is:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mydate = dol_mktime(12, 0 , 0, $_POST[&#039;mykeymonth&#039;], $_POST[&#039;mykeyday&#039;], $_POST[&#039;mykeyyear&#039;]);&lt;br /&gt;
print strftime(&#039;%A %d %B %Y&#039;, $mydate);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Add your own setup page (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs parameters, which are to be provided by the user, for proper setting up of the module.&lt;br /&gt;
&lt;br /&gt;
===Create your page to edit parameters===&lt;br /&gt;
If your module needs several parameters to be setup, you must create a page to edit options (these options will be saved in the [[Table llx_const|table &#039;&#039;&#039;llx_const&#039;&#039;&#039;]]).&lt;br /&gt;
Create a page named &#039;&#039;&#039;mymodule_setuppage.php&#039;&#039;&#039; that shows a form for possible options to update them into the above-mentioned table.&lt;br /&gt;
It is necessary to take an example from a page of the directory &#039;&#039;&#039;/admin&#039;&#039;&#039; that will show you the way to read/save your parameters.&lt;br /&gt;
Put this PHP page into the directory &#039;&#039;&#039;/admin&#039;&#039;&#039; of your module (e.g. mymodule/admin/mymodule_setuppage.php).&lt;br /&gt;
&lt;br /&gt;
===Modify the descriptor file of your module===&lt;br /&gt;
Then, within the descriptor file of your module, modify the variable &#039;&#039;&#039;config_page_url&#039;&#039;&#039; to set the name of this PHP page.&lt;br /&gt;
If the page is in the directory &#039;&#039;&#039;admin/&#039;&#039;&#039;, then the path is not required, e.g. like this:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;mymodule_setuppage.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the page is in the directory &#039;&#039;&#039;mymodule/admin/&#039;&#039;&#039;, then like this:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;mymodule_setuppage.php@mymodule&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Test your page===&lt;br /&gt;
Go into page &#039;&#039;&#039;Home-&amp;gt;Setup-&amp;gt;Modules&#039;&#039;&#039;, you should see a picture at the end of the line of your module to reach your setup page. Click on it, you should be able to view/edit parameters from your page.&lt;br /&gt;
&lt;br /&gt;
==Define your entries in menu (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you have created PHP pages, it is necessary that those pages can be reached from menu entries in Dolibarr menu.&lt;br /&gt;
&lt;br /&gt;
===Define your menu entries===&lt;br /&gt;
For this, you must define into the module descriptor, the array this-&amp;gt;menu that declares all menus added by your module.&lt;br /&gt;
This array contains entries that will appear once your module is activated.&lt;br /&gt;
The example module descriptor file &#039;&#039;&#039;modMyModule.class.php&#039;&#039;&#039; contains an example to declare a top menu and also its left menu entries.&lt;br /&gt;
&lt;br /&gt;
This is the example of code to declare your own menu entries in a module descriptor file:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Main menu entries&lt;br /&gt;
$this-&amp;gt;menu = array();			// List of menus to add&lt;br /&gt;
$r=0;&lt;br /&gt;
&lt;br /&gt;
// Add here entries to declare new menus&lt;br /&gt;
// Example to declare the Top Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;0,			// Put 0 if this is a top menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;top&#039;,			// This is a Top menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MyModule top menu&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;mymodule&#039;,&lt;br /&gt;
			&#039;leftmenu&#039;=&amp;gt;&#039;mymodule&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/mymodule/pagetop.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;mymodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users, 1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&lt;br /&gt;
// Example to declare a Left Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;&#039;fk_mainmenu=xxx&#039;,		    // Use &#039;fk_mainmenu=xxx&#039; or &#039;fk_mainmenu=xxx,fk_leftmenu=yyy&#039; where xxx is mainmenucode and yyy is a leftmenucode of parent menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;left&#039;,			        // This is a Left menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MyModule left menu 1&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;xxx&#039;,&lt;br /&gt;
                        &#039;leftmenu&#039;=&amp;gt;&#039;yyy&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/mymodule/pagelevel1.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;mymodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users,1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To show the menu or not depending on a permission, modify property &#039;&#039;&#039;perms&#039;&#039;&#039; in the array. See chapter on permissions later to see how to add permissions.&lt;br /&gt;
&lt;br /&gt;
===Test your menu entries===&lt;br /&gt;
Disable and re-enable your module under the Dolibarr module setup page, menus entries must appear (if property &#039;enabled&#039; is declaration array is ok).&lt;br /&gt;
&lt;br /&gt;
==Add your own permissions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you want to add new permissions.&lt;br /&gt;
&lt;br /&gt;
The way to define permissions that will manage your module is done inside the module descriptor created previously.&lt;br /&gt;
Modify line &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights_class = &#039;mymodule&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
with correct value for mymodule.&lt;br /&gt;
&lt;br /&gt;
Then you must fill the array $this-&amp;gt;rights with as many entries than different permissions you need to manage.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights[$r][0] = 10001;&lt;br /&gt;
$this-&amp;gt;rights[$r][1] = &#039;Label by default of permission&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][3] = 1;&lt;br /&gt;
$this-&amp;gt;rights[$r][4] = &#039;action&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][5] = &#039;subaction&#039;;&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Into $this-&amp;gt;rights[$r][0], put a permission id not already used (See into menu &#039;&#039;&#039;System info&#039;&#039;&#039; on a working installation of Dolibarr to know list of id already used by standard modules.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][3], put 1 if this permission must be granted automatically by default to any newly created user.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][1], put a label by default for permission (This label will be used if no translation can be found into the file &#039;&#039;&#039;admin.lang&#039;&#039;&#039; Translation key should be &amp;quot;Permission10001=My permission Label&amp;quot;).&lt;br /&gt;
Into $this-&amp;gt;rights[$r][4] and $this-&amp;gt;rights[$r][5], put an action and subaction string without spaces. You will be able to test if a user has the permission in your PHP source code with the sequence:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;action-&amp;gt;subaction) ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Define your own box (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs to provide one or several new boxes to show on home page.&lt;br /&gt;
&lt;br /&gt;
===Define your box===&lt;br /&gt;
For this, modify the array $this-&amp;gt;boxes into the module descriptor file.&lt;br /&gt;
All you have to do is to add 2 lines for each box file you will create into directory &#039;&#039;&#039;htdocs/mymodule/core/boxes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example:&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;file&#039;]=&#039;mybox0.php@mymodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;note&#039;]=&#039;My box 0&#039;&lt;br /&gt;
 ...&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;file&#039;]=&#039;myboxn.php@mymodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;note&#039;]=&#039;My box n&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then create files &#039;&#039;&#039;htdocs/mymodule/core/boxes/mybox0.php&#039;&#039;&#039;, &#039;&#039;&#039;htdocs/mymodule/core/boxes/mybox1.php&#039;&#039;&#039;... by copying an example from an existing box file (found into directory &#039;&#039;&#039;htdocs/core/boxes&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
===Test if your box is detected by Dolibarr===&lt;br /&gt;
Disable and enabled module.&lt;br /&gt;
&lt;br /&gt;
Go into menu &#039;&#039;&#039;Home - Setup - Boxes&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Your boxes must appear in the list of boxes you can activate. Activate the box and go on the home page to see if the box is showing correctly.&lt;br /&gt;
&lt;br /&gt;
==Define your own export (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module provides new predefined database export profiles (for its own tables or for already existing tables of another module).&lt;br /&gt;
&lt;br /&gt;
===Define export===&lt;br /&gt;
For this uncomment and modify arrays $this-&amp;gt;export_xxx in your module descriptor file.&lt;br /&gt;
&lt;br /&gt;
===Test your export===&lt;br /&gt;
Go into menu Tools -&amp;gt; Export. Your export will appear in the list of available predefined exports (if your module is enabled).&lt;br /&gt;
Choose it, you must see a list of all possible fields defined in the export arrays.&lt;br /&gt;
Choose on field and try to build an export file. If ok, try again with all fields.&lt;br /&gt;
&lt;br /&gt;
==Define your CSS styles (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If in your PHP pages, you use class styles that are not defined inside Dolibarr themes CSS (not recommanded).&lt;br /&gt;
&lt;br /&gt;
===Create and declare your style sheet===&lt;br /&gt;
Create a style sheet CSS named &#039;&#039;&#039;mymodule.css&#039;&#039;&#039; or &#039;&#039;&#039;mymodule.css.php&#039;&#039;&#039; and put it into directory &#039;&#039;&#039;htdocs/mymodule&#039;&#039;&#039;. You can have several CSS files per module.&lt;br /&gt;
Remember it&#039;s better to use existing styles already available by default into Dolibarr (The CSS file used by Dolibarr is file &#039;&#039;&#039;themes/mytheme/&#039;&#039;themename&#039;&#039;.css.php&#039;&#039;&#039;. Create your own CSS files only if you need absolutely to add not already existing styles.&lt;br /&gt;
&lt;br /&gt;
Once your style sheets are ready, declare them into your module descriptor file by modifying the property &#039;&#039;&#039;$this-&amp;gt;modules_parts&#039;&#039;&#039;.&lt;br /&gt;
Value to put here must be an array of relative URLs to your CSS files.&lt;br /&gt;
For example&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;module_parts = array(&#039;css&#039; =&amp;gt; array(&#039;/mymodule/css/mymodule.css.php&#039;,&#039;/mymodule/css/myother.css&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Test your style sheet===&lt;br /&gt;
Disable and enable your module.&lt;br /&gt;
&lt;br /&gt;
Go on the home page (index.php). Show the HTML source of the page.&lt;br /&gt;
&lt;br /&gt;
You should see into the HTML header, a line that declares your style sheet.&lt;br /&gt;
&lt;br /&gt;
==Add your Javascript functions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If in your PHP pages, you use javascript functions not available in Dolibarr (in file lib_head.js)&lt;br /&gt;
&lt;br /&gt;
If you need to use your own javascript functions inside your PHP pages, it is necessary to have your functions, defined into your javascript file &#039;&#039;&#039;htdocs/mymodule/js/mymodule.js&#039;&#039;&#039;, included into the HTML HEAD section.&lt;br /&gt;
To ask Dolibarr that forge this header to include your own javascript file, you must just provide it to the llxHeader() function called by your page.&lt;br /&gt;
&lt;br /&gt;
Example for page /htdocs/mymodule/mypage.php :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$morejs=array(&amp;quot;/mymodule/js/mymodule.js&amp;quot;);&lt;br /&gt;
llxHeader(&#039;&#039;,&#039;Titre&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,$morejs,&#039;&#039;,0,0); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Run your own code on any Dolibarr event (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you want to execute your own code once a common Dolibarr event has occurred (example: I want to update a table in my module when an invoice is created into Dolibarr), you must create a &#039;&#039;&#039;triggers&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
See also [[Interfaces_Dolibarr_toward_foreign_systems]]&lt;br /&gt;
and [[Interfaces_from_foreign_systems_toward_Dolibarr]]&lt;br /&gt;
&lt;br /&gt;
==Insert your code inside Dolibarr hooks positions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to add code or replace Dolibarr code into another situation than a business event (See the previous chapter for adding code during a business event).&lt;br /&gt;
&lt;br /&gt;
See page [[Hooks_system]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Add your own numbering rules==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you need a new rule for generated ref of elements that are not covered by existing rules.&lt;br /&gt;
&lt;br /&gt;
See page [[Create numbering module]].&lt;br /&gt;
&lt;br /&gt;
==Add your document template (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to personalized your own generated PDF or ODT documents.&lt;br /&gt;
&lt;br /&gt;
Note: To add this feature you don&#039;t need to create a module descriptor.&lt;br /&gt;
&lt;br /&gt;
Documentation to add your own template is available on page [[Create_a_PDF_document_template]] or [[Create_an_ODT_document_template]].&lt;br /&gt;
&lt;br /&gt;
==Add your skin (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to personalized your colors/fonts/images.&lt;br /&gt;
&lt;br /&gt;
Note: To add this feature you don&#039;t need to create a module descriptor.&lt;br /&gt;
&lt;br /&gt;
To add your own skin, read page [[Skins]].&lt;br /&gt;
&lt;br /&gt;
=Some coding rules and predefined functions=&lt;br /&gt;
The coding rules to be followed are defined in the [[Developer documentation]], under section &amp;quot;General Information - Language and standards development&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A lot of predefined features for developers are also available and described into page [[Developer documentation]] under section &amp;quot;Technical components of Dolibarr&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=Create a package to distribute and install your module=&lt;br /&gt;
This process must be used to generate a package to submit it on the http://www.dolistore.com marketplace.&lt;br /&gt;
But you can use it to have a package easy to distribute on your own network.&lt;br /&gt;
&lt;br /&gt;
*Go into the directory &#039;&#039;&#039;/build&#039;&#039;&#039; and copy the file &#039;&#039;&#039;makepack-dolibarrmodules.conf&#039;&#039;&#039; into &#039;&#039;&#039;makepack-mymodule.conf&#039;&#039;&#039;. Warning, this directory may not be provided in some packages of stable versions. If so, it can be retrieved from the snapshot available for download on the Dolibarr website in area &amp;quot;Development version&amp;quot; (taken in this case the whole build directory which is autonomous and independent directory).&lt;br /&gt;
&lt;br /&gt;
Edit this file to add a list of file names for all new files you created for your module (module descriptor, new sql tables files, php page, images, etc...)&lt;br /&gt;
&lt;br /&gt;
*Run the script via Perl (need the Perl version 5.0 or later):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
perl makepack-dolibarrmodule.pl&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The script asks you the name of your module, its major and minor version. A file &#039;&#039;&#039;mymodule.zip &#039;&#039;&#039; will then be manufactured containing your module ready to be deployed.&lt;br /&gt;
&lt;br /&gt;
*The person who receives your module must then place the file in the root directory of a Dolibarr installation and perform the command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tar -xvf mymodule.zip&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*If you want your module to be public, you can submit it (the zip file) on Dolibarr marketplace website: {{LinkToPluginDownload}} (you must create an account first and be logged to use the link &amp;quot;Submit a module/product&amp;quot;).&lt;br /&gt;
**If your module was built correctly, the file will be validated later.&lt;br /&gt;
**If quality is enough and license permits it, the code might be added inside main Dolibarr sources (except if you disagree for that).&lt;br /&gt;
&lt;br /&gt;
=Enabling/activation condition of external module on DoliStore=&lt;br /&gt;
&lt;br /&gt;
See [[Module_Dolistore_Validation_Rules|Validation Rules]]&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>ALSOFT</name></author>
	</entry>
	<entry>
		<id>https://wiki.dolibarr.org/index.php?title=Language_and_development_rules&amp;diff=49919</id>
		<title>Language and development rules</title>
		<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php?title=Language_and_development_rules&amp;diff=49919"/>
		<updated>2021-03-08T11:29:16Z</updated>

		<summary type="html">&lt;p&gt;ALSOFT: /* Index performance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- BEGIN origin interlang links --&amp;gt;&lt;br /&gt;
&amp;lt;!-- You can edit this section but do NOT remove these comments&lt;br /&gt;
     Links below will be automatically replicated on translated pages by PolyglotBot --&amp;gt;&lt;br /&gt;
[[de:Sprachen_und_Programmierregeln]]&lt;br /&gt;
[[fr:Langages_et_normes]]&lt;br /&gt;
[[es:Lenguaje_y_Normas_de_Desarrollo]]&lt;br /&gt;
[[zh:语言和开发规则]]&lt;br /&gt;
&amp;lt;!-- END interlang links --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{TemplateDocDevEn}}&lt;br /&gt;
&lt;br /&gt;
These are some rules on language, syntax and norm we use in the Dolibarr project:&lt;br /&gt;
&lt;br /&gt;
=Versions=&lt;br /&gt;
&lt;br /&gt;
*Dolibarr must work on:&lt;br /&gt;
&lt;br /&gt;
#All OS (Windows, Linux, MACOS...)&lt;br /&gt;
#PHP {{PHPMinVersion}} (Must work with no need of complementary PHP module, except module to PHP module to access database).&lt;br /&gt;
#MySQL {{MySqlMinVersion}}&lt;br /&gt;
&lt;br /&gt;
=Copyright Norms=&lt;br /&gt;
&lt;br /&gt;
*All PHP files must start with a header that looks like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
/* Copyright (C) YYYY John Doe  &amp;lt;email@email.com&amp;gt;&lt;br /&gt;
 *&lt;br /&gt;
 * Licence information&lt;br /&gt;
 */&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
When you edit an existing file of project, you must add a Copyright line under others.&lt;br /&gt;
&lt;br /&gt;
=PHP Norms=&lt;br /&gt;
==PHP==&lt;br /&gt;
&lt;br /&gt;
*Dolibarr is written with PHP and supports all versions of PHP higher than {{PHPMinVersion}}. All files must end with extension .php&lt;br /&gt;
&lt;br /&gt;
*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..&lt;br /&gt;
&lt;br /&gt;
*Other operators ($HTTP_SERVER_GET, ...) are now deprecated in PHP, so they must not be used. Code must work if option &#039;&#039;&#039;register_long_arrays&#039;&#039;&#039; is set to off. Moreover, the code must work when PHP option &#039;&#039;&#039;register_globals&#039;&#039;&#039; is off (recommended by PHP). It must also work  if the option &#039;&#039;&#039;register_globals&#039;&#039;&#039; is on (by default on a lot of installations).&lt;br /&gt;
&lt;br /&gt;
*Do not use &#039;&#039;&#039;&amp;lt;s&amp;gt;PHP_SELF&amp;lt;/s&amp;gt;&#039;&#039;&#039;. Use instead &#039;&#039;&#039;$_SERVER[&amp;quot;PHP_SELF&amp;quot;]&#039;&#039;&#039;. Also, Dolibarr framework sanitizes content of $_SERVER[&amp;quot;PHP_SELF&amp;quot;] variable (into main.inc.php file, before any business code).&lt;br /&gt;
&lt;br /&gt;
*When several variables must be initialized with the same value, you must use individual declarations (separated by ;)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$var1 = 1;&lt;br /&gt;
$var2 = 1;&lt;br /&gt;
$var3 = 1;&lt;br /&gt;
&amp;lt;/sousyntaxhighlightrce&amp;gt;&lt;br /&gt;
instead of&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$var1 = $var2 = $var3 = 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which is slower.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Strings====&lt;br /&gt;
&lt;br /&gt;
*Strings must be have variables outside of the quote.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
print &amp;quot;My text show my &amp;quot;.$variable.&amp;quot; !\n&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Comments====&lt;br /&gt;
&lt;br /&gt;
*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&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
/* Bloc of comment&lt;br /&gt;
 *&lt;br /&gt;
 * End of bloc&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
$monobjet = new MonObjet($db);&lt;br /&gt;
$result=$monobjet-&amp;gt;fetch($idobject);&lt;br /&gt;
&lt;br /&gt;
for ($i = 1 , $i &amp;lt; 2 ; $i++) {&lt;br /&gt;
    // comment on one line&lt;br /&gt;
    print $i;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function myFunction($param1, $param2)&lt;br /&gt;
{&lt;br /&gt;
    // code&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Functions must return a value equal or higher than 0 if successful and strictly lower than 0 if error.&lt;br /&gt;
&lt;br /&gt;
*No dead code (code never used) into Dolibarr core code (code used by external modules only must be included within the external modules).&lt;br /&gt;
&lt;br /&gt;
*Use &amp;quot;include_once&amp;quot; for anything with functions or class definitions in it (like *.class.php and *.lib.php files), use &amp;quot;include&amp;quot; for template-style php with files containing common part of HTML and PHP code (like *.inc.php and *.tpl.php files).&lt;br /&gt;
&lt;br /&gt;
*Coding style to use is the &#039;&#039;&#039;PSR-12&#039;&#039;&#039; (https://www.php-fig.org/psr/psr-12/). Only rules tagged &amp;quot;MUST&amp;quot; are currently required. So note however the exceptions:&lt;br /&gt;
**Length of line: PSR-12 mention we can&#039;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 &#039;&#039;&#039;1000&#039;&#039;&#039; characters (having line larger than this may return errors on Continuous Integration tests).&lt;br /&gt;
**Tabs are allowed: The other exception is that we don&#039;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 &amp;quot;Keep spaces/tabs as it is&amp;quot;, however, you can activate the option &amp;quot;Remove spaces at end of lines&amp;quot;.&lt;br /&gt;
**We allow elements of an array on same line and we do not always add a new line at end of each element.&lt;br /&gt;
**Note 1: The following rule are very important to follow:&lt;br /&gt;
***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.&lt;br /&gt;
***Smart tags PHP are not used. PHP code section must start with &#039;&#039;&#039;&amp;lt;?php&#039;&#039;&#039;&lt;br /&gt;
**Note 2: You can use the file &#039;&#039;&#039;dev/setup/codesniffer/ruleset.xml&#039;&#039;&#039; as rule file to control coding style with PHPCodeSniffer.&lt;br /&gt;
**Note 3: You can use the file &#039;&#039;&#039;dev/setup/eclipse/PSR-12 [built-in].xml&#039;&#039;&#039; as rule file to setup Eclipse syntax formater.&lt;br /&gt;
**Note 4: You may note that current code is not yet compliant with the PSR-12. The reason is that we must &amp;quot;now&amp;quot; follow the &amp;quot;MUST&amp;quot; rules of PSR-12, but it wasn&#039;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.&lt;br /&gt;
&lt;br /&gt;
==Classes and properties structures==&lt;br /&gt;
&lt;br /&gt;
Some properties of classes are found in different classes. To avoid having different names, we will use the following PHP properties names:&lt;br /&gt;
&lt;br /&gt;
{{TemplatePHPFields}}&lt;br /&gt;
&lt;br /&gt;
=SQL rules=&lt;br /&gt;
&lt;br /&gt;
==DDL file format==&lt;br /&gt;
Files containing definition of the database structure (DDL files) must be &#039;&#039;&#039;2 per table&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
*The first file defines the table and its fields. The file name contains the table name, e.g. like this: &amp;lt;tt&amp;gt;llx_&#039;&#039;mytable&#039;&#039;.sql&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A comment will be added for each field to explain its usage.&lt;br /&gt;
&lt;br /&gt;
*The second file defines all foreign keys, performance indexes or other constraints and the file name will be like: &amp;lt;tt&amp;gt;llx_&#039;&#039;mytable&#039;&#039;.key.sql&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These files must be stored in the directory &#039;&#039;&#039;install/mysql/tables&#039;&#039;&#039; for all standard files or &#039;&#039;&#039;mymodule/tables&#039;&#039;&#039; for tables provided by an external module.&lt;br /&gt;
&lt;br /&gt;
Example: &#039;&#039;&#039;file for creating the table llx_mytable will be llx_mytable.sql&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- ===========================================================================&lt;br /&gt;
-- Copyright (C) 2013 Author &amp;lt;email@author.com&amp;gt;&lt;br /&gt;
-- &lt;br /&gt;
-- This program is free software; you can redistribute it and/or modify&lt;br /&gt;
-- it under the terms of the GNU General Public License as published by&lt;br /&gt;
-- the Free Software Foundation; either version 3 of the License, or&lt;br /&gt;
-- (at your option) any later version.&lt;br /&gt;
--&lt;br /&gt;
-- This program is distributed in the hope that it will be useful,&lt;br /&gt;
-- but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
-- GNU General Public License for more details.&lt;br /&gt;
--&lt;br /&gt;
-- You should have received a copy of the GNU General Public License&lt;br /&gt;
-- along with this program. If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
-- ===========================================================================&lt;br /&gt;
&lt;br /&gt;
create table llx_mytable&lt;br /&gt;
(&lt;br /&gt;
  rowid       integer NOT NULL AUTO_INCREMENT PRIMARY KEY,&lt;br /&gt;
  ref	      varchar(30)       NOT NULL,		-- object reference number&lt;br /&gt;
  entity      integer DEFAULT 1 NOT NULL,	        -- multi company id&lt;br /&gt;
  ref_ext     varchar(255),-- reference into an external system (not used by dolibarr)&lt;br /&gt;
  field_one   integer,&lt;br /&gt;
  field_two   integer NOT NULL,&lt;br /&gt;
  fk_field    integer,&lt;br /&gt;
  field_date  datetime,&lt;br /&gt;
  datec       timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,,   -- creation datetime&lt;br /&gt;
  tms         timestamp,    -- update time stamp&lt;br /&gt;
  fk_user_author integer NOT NULL,                     -- Author, foreign key of llx_user&lt;br /&gt;
  fk_user_mod    integer NOT NULL,                      -- Last updater, foreign key of llx_user&lt;br /&gt;
  import_key	varchar(14)                -- Use by import process&lt;br /&gt;
)type=innodb;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: &#039;&#039;&#039;file for creating keys/indexes for the table llx_mytable will be llx_mytable.key.sql&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- ===========================================================================&lt;br /&gt;
-- Copyright (C) 2013 Author &amp;lt;email@author.com&amp;gt;&lt;br /&gt;
-- &lt;br /&gt;
-- This program is free software; you can redistribute it and/or modify&lt;br /&gt;
-- it under the terms of the GNU General Public License as published by&lt;br /&gt;
-- the Free Software Foundation; either version 3 of the License, or&lt;br /&gt;
-- (at your option) any later version.&lt;br /&gt;
--&lt;br /&gt;
-- This program is distributed in the hope that it will be useful,&lt;br /&gt;
-- but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
-- GNU General Public License for more details.&lt;br /&gt;
--&lt;br /&gt;
-- You should have received a copy of the GNU General Public License&lt;br /&gt;
-- along with this program. If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
-- ===========================================================================&lt;br /&gt;
&lt;br /&gt;
ALTER TABLE llx_mytable ADD UNIQUE uk_mytable_field (field_one, field_two);&lt;br /&gt;
&lt;br /&gt;
ALTER TABLE llx_mytable ADD CONSTRAINT fk_mytable_fk_field FOREIGN KEY (fk_field) REFERENCES llx_matablepere (rowid);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Table and fields structures==&lt;br /&gt;
&lt;br /&gt;
*Structure of tables.&lt;br /&gt;
&lt;br /&gt;
When you create a new table, it is recommended to use the same conventions as other Dolibarr tables. This means the following fields:&lt;br /&gt;
 - rowid INTEGER AUTO_INCREMENT PRIMARY KEY    that is technical id of record&lt;br /&gt;
 - entity INTEGER default 1                    that is id for the multicompany feature&lt;br /&gt;
 - date_creation   datetime                    that is the creation date&lt;br /&gt;
 - tms             timestamp                   that will contain date of last modification (the database manages this field automatically, no need to manage it by the code, just create the field)&lt;br /&gt;
 - date_valid      datetime                    that is the validation date (if applicable)&lt;br /&gt;
 - import_key      varchar(32)                 that will contains the import code YYYYMMDDHHMMSS if you make mass import.&lt;br /&gt;
 - status          smallint                    to store a status&lt;br /&gt;
Eventually&lt;br /&gt;
 - fk_user_creat or fk_user_author integer that is the id of user making creation&lt;br /&gt;
 - fk_user_modif integer that is the id of user making change&lt;br /&gt;
 - fk_user_valid integer that is the id of user validating record (if applicable)&lt;br /&gt;
 - fk_soc integer that is the ID of the Third party (if applicable)&lt;br /&gt;
&lt;br /&gt;
Note field:&lt;br /&gt;
 - note_private text for private comment of the object&lt;br /&gt;
 - note_pubic text for public comment of the object&lt;br /&gt;
or &lt;br /&gt;
 - note text if there is no need to have private and public&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Type of fields:&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
 - integer for a primary key, an integer or any of foreign key (bigint may also be accepted for very large tables)&lt;br /&gt;
 - smallint for a small number (like for a status) or a boolean&lt;br /&gt;
 - double(24,8) for any amount&lt;br /&gt;
 - double(6,3) for any vat rate&lt;br /&gt;
 - real for a quantity&lt;br /&gt;
 - varchar for a string (also if length is 1, the type char is more and more deprecated)&lt;br /&gt;
 - timestamp for a field date+time that is automatically updated&lt;br /&gt;
 - datetime for a field date+time&lt;br /&gt;
 - date for a field date&lt;br /&gt;
 - text or medium text for large fields (no index allowed on such fields)&lt;br /&gt;
&lt;br /&gt;
All business rules must be on same place, into PHP code, not into client, neither into database, that&#039;s why type enum is also not allowed.&lt;br /&gt;
Other type are not allowed for compatibility reasons. &lt;br /&gt;
&lt;br /&gt;
*All tables has a prefix to avoid name conflicts with other projects. In current version this prefix is fixed ans can&#039;t be modified. Its value is &amp;lt;tt&amp;gt;llx_&amp;lt;/tt&amp;gt;. In a future version this value should be modified during installation process.&lt;br /&gt;
&lt;br /&gt;
==Primary keys==&lt;br /&gt;
The primary key of a table must be called &amp;lt;tt&amp;gt;rowid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Some old tables does not use this rule and use a primary key called &amp;lt;tt&amp;gt;id&amp;lt;/tt&amp;gt; (ie [[Table llx_c_actioncomm]]), but the reason is history and this should not happen anymore.&lt;br /&gt;
&lt;br /&gt;
==Foreign keys==&lt;br /&gt;
Name of a foreign key must start with the prefix &amp;lt;tt&amp;gt;fk_&amp;lt;/tt&amp;gt; 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).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&#039;&#039;fk_facture_fourn_fk_soc&#039;&#039;  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)&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==Alternative keys==&lt;br /&gt;
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 &amp;lt;tt&amp;gt;uk_&amp;lt;/tt&amp;gt; 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).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&#039;&#039;uk_societe_code_client&#039;&#039; is a unique key on table llx_societe on field code_client.&lt;br /&gt;
&lt;br /&gt;
==Index performance==&lt;br /&gt;
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 &amp;lt;tt&amp;gt;idx_&amp;lt;/tt&amp;gt; then the table name and then the field name.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&#039;&#039;idx_societe_user_create&#039;&#039; is a performance index on table llx_societe for field user_create&lt;br /&gt;
&lt;br /&gt;
==SQL Coding rules==&lt;br /&gt;
&lt;br /&gt;
*Alias usage/Fields naming&lt;br /&gt;
&lt;br /&gt;
When doing select, we can use alias to simplify writing/reading of requests:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
select chp1, chpxxx2 as chp2 from table2 as t1, table2 as t2 where t1.chpx = t2.chpy&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
However, we must not used alias for update request as they are not compatible with Mysql 3.1.&lt;br /&gt;
&lt;br /&gt;
*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:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT field_a, field_b, field_c FROM table_1 WHERE field_d = &#039;$id&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*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&#039;s PHP that has the good vision. There is really a wrong value into database. By removing quotes on numbers, no problem occurs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
Good:     INSERT INTO table_1 (field_txt, field_num) VALUES (&#039;txt&#039;, 412.62)&lt;br /&gt;
Bad:      INSERT INTO table_1 (field_txt, field_num) VALUES (&#039;txt&#039;, &#039;412.62&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;real&amp;quot; numbers, so numbers must be, as soon as they are affected, cleaned with function price2num with second parameter defined to :&lt;br /&gt;
&#039;MU&#039; (for unit prices), &#039;MT&#039; (for total prices) or &#039;MS&#039; (otherwise) depending on usage of number. (see function documentation)&lt;br /&gt;
&lt;br /&gt;
*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.&lt;br /&gt;
&lt;br /&gt;
For example, don&#039;t do:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$sql=&amp;quot;SELECT rowid FROM table where datefield = NOW()&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
but do:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$sql=&amp;quot;SELECT rowid FROM table where datefield = &#039;&amp;quot;.$this-&amp;gt;db-&amp;gt;idate(dol_now()).&amp;quot;&#039;&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, don&#039;t do:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$sql=&amp;quot;SELECT rowid FROM table where DATEDIFF(table.datefield, NOW()) &amp;gt; 7&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
but do:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$sql=&amp;quot;SELECT rowid FROM table where datefield &amp;lt; &#039;&amp;quot;.$this-&amp;gt;db-&amp;gt;idate(dol_now() - (7 * 24 * 3600)).&amp;quot;&#039;&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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&#039;t use the index on field, resulting on very bad performance compared to solution without the datediff.&lt;br /&gt;
&lt;br /&gt;
*Use $db-&amp;gt;ifsql for SQL IF&lt;br /&gt;
&lt;br /&gt;
Do not include the IF into your forged SQL request. But use instead $db-&amp;gt;ifsql() method to you will make a SQL IF that is compatible with all SQL databases.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using Database triggers==&lt;br /&gt;
Using Database triggers is not allowed into the code of Dolibarr, so you should have no troubles with Database triggers. &lt;br /&gt;
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 &amp;quot;business rules&amp;quot; of your application into the database where most other rules are managed by the code itself creating conflict or code that can&#039;t be debugged with a step by step debugger, ...&lt;br /&gt;
There is tons of reason why we do not recommand to use database triggers in your own development. &lt;br /&gt;
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&#039;t work for more than 50% of users.&lt;br /&gt;
&lt;br /&gt;
==MySQL-MariaDB specificity==&lt;br /&gt;
&lt;br /&gt;
*Tables must be declared with format InnoDB.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
*Dolibarr MUST work even if MySQL option &#039;&#039;&#039;strict&#039;&#039;&#039; is active.&lt;br /&gt;
&lt;br /&gt;
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)&lt;br /&gt;
{{MySqlStrictMode}}&lt;br /&gt;
&lt;br /&gt;
==PostgreSQL specificities==&lt;br /&gt;
Only MySQL files must be maintained.&lt;br /&gt;
Those files are converted &amp;quot;on the fly&amp;quot; by the database Dolibarr driver.&lt;br /&gt;
&lt;br /&gt;
There is an exception for the SQL &amp;quot;UPDATE FROM&amp;quot;: &lt;br /&gt;
&lt;br /&gt;
MySQL Syntax:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE table_taget as target, table_source as source SET fieldtarget=source.fieldsource&lt;br /&gt;
WHERE source.rowid=target.rowid;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PgSQL Syntax:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE table_taget as target SET fieldtarget=source.fieldsource&lt;br /&gt;
FROM table_source as source WHERE source.rowid=target.rowid;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is no native SQL requests &amp;quot;UPDATE FROM&amp;quot; in all Dolibarr core. But if you use one in your own code of your module, you should do :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
if ($this-&amp;gt;db-&amp;gt;type==&#039;pgsql&#039;) {&lt;br /&gt;
$sql=&amp;quot;UPDATE table_taget as target SET fieldtarget=source.fieldsource&lt;br /&gt;
FROM table_source as source WHERE source.rowid=target.rowid&amp;quot;;&lt;br /&gt;
} else {&lt;br /&gt;
$sql= &amp;quot;UPDATE table_taget as target, table_source as source SET fieldtarget=source.fieldsource&lt;br /&gt;
WHERE source.rowid=target.rowid&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=HTML norms=&lt;br /&gt;
==Syntax rules==&lt;br /&gt;
&lt;br /&gt;
*HTML used must be HTML compliant and not XHTML. All attributes of HTML tags must be in lower case and quoted with &amp;quot;.&lt;br /&gt;
&lt;br /&gt;
*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().&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
print &#039;&amp;lt;a href=&amp;quot;&#039;.dol_buildpath(&#039;/mydir/mypage.php&#039;).&#039;&amp;quot;&amp;gt;&#039;.img_picto(&#039;Texte alt&#039;,&#039;namepictopng&#039;,&#039;&#039;).&#039;&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*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=&amp;quot;20px&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
*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 &amp;quot;$conf-&amp;gt;use_javascript_ajax&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
if ($conf-&amp;gt;use_javascript_ajax) {&lt;br /&gt;
...  // php code generating javascript here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Popup windows must not be used, except for tooltips (and must have a condition as explained before).&lt;br /&gt;
&lt;br /&gt;
*External scripts must be written in Perl if they can&#039;t be written in PHP. Usage of another language is not forbidden but must be argued before in the development mailing-list.&lt;br /&gt;
&lt;br /&gt;
==External templating framework ?==&lt;br /&gt;
There is ton of frameworks to provide a templating language of an HTML page. The best and faster is just called &amp;quot;PHP&amp;quot;, and because Dolibarr already depends on PHP, there is no need to introduce a dependency on a third language.&lt;br /&gt;
&lt;br /&gt;
All templating frameworks are just preprocessor, BEFORE PHP. It can&#039;t be faster than PHP alone. When we say &amp;quot;speed is increased because templating framework use a cache&amp;quot;, you must read in fact &amp;quot;the overtime spent by the framework is reduced by cache, not the speed of processing PHP file&amp;quot;. We should say &amp;quot;any templating framework has an overload over PHP, the cache of the templating framework just reduces the slowing effect of using this framework&amp;quot;, but not &amp;quot;the speed is increased, it is always decreased compared to pure PHP&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Above all, having a templating system is completely possible by doing a &amp;quot;&#039;&#039;&#039;.tpl.php&#039;&#039;&#039;&amp;quot; file that dos not contains any logic code, but only HTML and &amp;quot;echo&amp;quot;. 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.&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=Dolibarr norms and code skeleton=&lt;br /&gt;
&lt;br /&gt;
==Skeleton code==&lt;br /&gt;
To standardize the code, and to speed up the development of new components in Dolibarr, you&#039;ll find skeletons of files fully prepared in the directory &#039;&#039;&#039;htdocs/modulebuilder/templates/&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
*1 file that serves as an example of the module description: &#039;&#039;&#039;myModule.class.php&#039;&#039;&#039;&lt;br /&gt;
*1 file that serves as an example of code for creating a new class: &#039;&#039;&#039;skeleton_class.class.php&#039;&#039;&#039;&lt;br /&gt;
*1 file that serves as an example of code for creating a new page: &#039;&#039;&#039;skeleton_page.php&#039;&#039;&#039;&lt;br /&gt;
*1 file that serves as an example of code for creating a script for executing command lines: &#039;&#039;&#039;skeleton_script.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
Use it as an example.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==Dates and Timezones==&lt;br /&gt;
Dolibarr is an application that is multi-user and multi-location. It&#039;s therefore necessary to store dates in the right format. To avoid problems with conversions, the following rules should be applied:&lt;br /&gt;
&lt;br /&gt;
*A date into memory must always be stored with Timestamp GMT format.&lt;br /&gt;
*A date stored into database, is the GMT Timestamp of date submitted into the request usng the &amp;lt;b&amp;gt;PHP server&amp;lt;/b&amp;gt; timezone. This does not apply to date update automatically by database (fields &#039;&#039;&#039;tms&#039;&#039;&#039; into database).&lt;br /&gt;
&lt;br /&gt;
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 &#039;19700101030000&#039; (PHP convert into its TZ hour and database will unconvert it using its timezone too that is same than PHP).&lt;br /&gt;
&lt;br /&gt;
All select methods should translate date fields, that are with format TZ of database (&#039;19700101030000&#039;), into a timestamp field by calling the method db-&amp;gt;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-&amp;gt;idate (you may find examples into skeleton).&lt;br /&gt;
&lt;br /&gt;
*Dates that are updated automatically (field &#039;&#039;&#039;tms&#039;&#039;&#039; into database) contains a GMT Timestamp GMT of date when change is done. The select will also use the db-&amp;gt;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.&lt;br /&gt;
&lt;br /&gt;
*Manipulation date with PHP must be done using the Dolibarr date functions: &#039;&#039;&#039;dol_now(), dol_mktime(), dol_stringtotime(), dol_getdate(), dol_time_plus_duree()&#039;&#039;&#039;. You may also find other functions available into file &#039;&#039;&#039;date.lib.php&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==UTF8/ISO encoding==&lt;br /&gt;
Dolibarr stores data in the following way:&lt;br /&gt;
&lt;br /&gt;
*In database, data is stored in UTF8 or ISO. It depends on the database&#039;s pagecode therefore these options are set at creation time. In any case, Dolibarr&#039;s database driver (in lib/database) deals with it to convert from/to UTF8 at insertion and readout.&lt;br /&gt;
*Memory data is stored in UTF8 (PHP object instances).&lt;br /&gt;
*Web pages are returned and rendered into UTF8&lt;br /&gt;
&lt;br /&gt;
==Float numbers, amount and calculation==&lt;br /&gt;
With PHP, like other languages (Java for exemple), non integer data (float, real, double) are not reliable for calculation.&lt;br /&gt;
Try to make for example &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
print 239.2 - 229.3 - 9.9;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You wont get zero but a very small decimal number. If you get zero her, you should be able to find other examples that don&#039;t work.&lt;br /&gt;
Problem of float is general, so a variable that is a result of a calculation using decimal numbers must ALWAYS be cleaned using the function &#039;&#039;&#039;price2num()&#039;&#039;&#039; with the econd parameter to: &#039;MU&#039;, &#039;MT&#039; or &#039;MS&#039; depending on need (see description of function).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
print price2num(239.2 - 229.3 - 9.9, &#039;MT&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If data manipulated is not an amount, then using MU, MT, MS has no sense, and you must use the function &#039;&#039;&#039;round()&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Creation of tables==&lt;br /&gt;
Do not create tables, on the fly, during execution by a standard user, we mean, during current usage of software.&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==Comparing version==&lt;br /&gt;
If your code need to make different things depending on Dolibarr version, you can use the following tip to detect and compare versions&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$version=preg_split(&#039;/[\.-]/&#039;,DOL_VERSION);&lt;br /&gt;
if (versioncompare($version,array(5,0,-4)) &amp;gt;= 0) { //mycode for 5.0 only; }	// For dolibarr 5.0.* (the -4 means we include also alpha, beta, rc and rcX)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But this solution need to include the function versioncompare. An alternative solution to test version is to do:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
if ((float) DOL_VERSION &amp;gt;= 5.0) { //mycode for 5.0 only; }	// For dolibarr 5.0.*&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Logs==&lt;br /&gt;
Add logs to your code using function&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
dol_syslog($yourmessage, LOG_INFO|LOG_DEBUG|LOG_WARNING|LOG_ERR);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Working directory==&lt;br /&gt;
If you need to create a working directory, into your code, refer to it with &lt;br /&gt;
&#039;&#039;&#039;DOL_DATA_ROOT.&#039;/mymodule&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The directory can be created into your code by the following function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$mymoduledir=DOL_DATA_ROOT.&#039;/mymodule&#039;;&lt;br /&gt;
dol_mkdir($mymoduledir);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need a directory to store temporary data, this directory must be &#039;&#039;&#039;DOL_DATA_ROOT.&#039;/mymodule/temp&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Design patterns and Object programming=&lt;br /&gt;
&lt;br /&gt;
==Creation design patterns (GoF)==&lt;br /&gt;
Design patterns defined by the Gang Of Four (see wikipédia on [[w:Design patterns|Design patterns]]).&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==Structure design patterns (GoF)==&lt;br /&gt;
Design patterns defined by the Gang Of Four (see wikipédia on [[w:Design patterns|Design patterns]]). &lt;br /&gt;
No usage of such patterns is required.&lt;br /&gt;
&lt;br /&gt;
==Behavior design patterns (GoF)==&lt;br /&gt;
Design patterns defined by the Gang Of Four (see wikipédia on [[w:Design patterns|Design patterns]]). &lt;br /&gt;
No usage of such patterns is required.&lt;br /&gt;
&lt;br /&gt;
==Design patterns of enterprise (Martin Fowler)==&lt;br /&gt;
&lt;br /&gt;
===Patterns of code organization===&lt;br /&gt;
[[w:Martin Fowler|Martin Fowler]] has identified 3 ways to organize code:&lt;br /&gt;
&lt;br /&gt;
*The &#039;&#039;&#039;Transaction Script&#039;&#039;&#039; (The source code is linear for each user action).&lt;br /&gt;
&lt;br /&gt;
This is the old school used by all procedural languages.&lt;br /&gt;
Inconvenient: Redundancy of code. Need to know the physical model of data to develop.&lt;br /&gt;
&lt;br /&gt;
*The &#039;&#039;&#039;Domain Model&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This notion is available with object languages. It is business process (to identify before) that are used for objects classes.&lt;br /&gt;
Inconvenient: Model very complex to maintain.&lt;br /&gt;
&lt;br /&gt;
*The &#039;&#039;&#039;Table Module&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This is a mix between 2 previous where we have only one unique class for each table of database.&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; As shown in code skeletons (see previous chapter), Dolibarr uses concept of &#039;&#039;&#039;Table Module&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Communication between business logic - data (ORM)===&lt;br /&gt;
&lt;br /&gt;
There are 3 ways to make links:&lt;br /&gt;
&lt;br /&gt;
*The &#039;&#039;&#039;Table And Row Data Gateway&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Example: This mode is used by some ORM Frameworks, like &#039;&#039;&#039;iBatis&#039;&#039;&#039; (http://ibatis.apache.org/).&lt;br /&gt;
&lt;br /&gt;
*The &#039;&#039;&#039;Active Record&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Example: This mode is used for Dolibarr development and most PHP software that includes their own framework and best practices.&lt;br /&gt;
&lt;br /&gt;
*The &#039;&#039;&#039;Data Mapper&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
More &amp;quot;purist&amp;quot; on paper (closer of business), this method also has the disadvantage of being more complex in practice.&lt;br /&gt;
&lt;br /&gt;
Example: This is the choice if you use the ORM Framework &#039;&#039;&#039;Propel&#039;&#039;&#039; (http://propel.phpdb.org/trac/). We find this model in heavier applications, based on this ORM among others.&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; For Dolibarr development, it is recommended to use the connection mode &#039;&#039;&#039;Active Record&#039;&#039;&#039;, 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).&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
&lt;br /&gt;
==Design pattern for Graphic interfaces (MVC)==&lt;br /&gt;
There are several design patterns for user interfaces (MVC, MVP, MVVM).&lt;br /&gt;
Many confuse this design pattern with that of using a template framework. It&#039;s unrelated. A template framework (see previous point) is only linked to the &amp;quot;V&amp;quot; part of these models.&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; Dolibarr uses the &#039;&#039;&#039;MVC&#039;&#039;&#039; Design Pattern. Part M is materialized by a DAO class containing the CRUD (Create-Read-Update-Delete) methods for accessing the table.&lt;br /&gt;
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&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Actions&lt;br /&gt;
 * /&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is followed by the part of code V (Vue), well separated from the C by the tag&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * View&lt;br /&gt;
 * /&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This mode of separation has had a neutral effect on new developments but has made it possible to reduce the time required for maintenance and fixing bugs so significantly that it is not envisaged to switch to another type of separation (yes the findings made in real life are not always those expected by school theory). The important thing remains that there is always a separation between C and V, no matter how this separation is materialized, as long as it is (Reminder: Do not confuse the notion of separation of C and V with the notion of separation of the code to feed the data of a View and of the code to format the View, this a principle of separation relating to the Design Pattern of Vue, see next point).&lt;br /&gt;
&lt;br /&gt;
==Design pattern for Views - Presentation==&lt;br /&gt;
There are frameworks that specialize in Vue Design Pattern, the part of formatting the screen seen by the user.&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
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&#039; code.&lt;br /&gt;
&lt;br /&gt;
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.&lt;/div&gt;</summary>
		<author><name>ALSOFT</name></author>
	</entry>
	<entry>
		<id>https://wiki.dolibarr.org/index.php?title=List_of_modules_id&amp;diff=49916</id>
		<title>List of modules id</title>
		<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php?title=List_of_modules_id&amp;diff=49916"/>
		<updated>2021-03-07T06:06:02Z</updated>

		<summary type="html">&lt;p&gt;ALSOFT: /* ID 100000 - 499999 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Core]]&lt;br /&gt;
{{TemplateDocDevEn}}&lt;br /&gt;
{{TemplateDocDevEs}}&lt;br /&gt;
{{TemplateDocDevFr}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Flag en}}&lt;br /&gt;
This page list all reserved modules numbers / ID. If you build or want to build your own modules (like this [[:Category:Complementary_modules|complementary module]]), you should take an ID range here. Please pick range into existing holes first.&lt;br /&gt;
&lt;br /&gt;
{{Flag fr}}&lt;br /&gt;
Cette page recense tous les numéros / ID réservés de modules. Si vous avez réalisé ou voulez réaliser vos propres modules (comme les [[:Category:Modules complémentaires|modules complémentaires suivant]]), vous devriez prendre une plage d&#039;ID ici. Merci de prendre dans les trous existant en priorité !&lt;br /&gt;
&lt;br /&gt;
{{Flag sp}}&lt;br /&gt;
Esta página contiene un listado de todos los id reservados para los módulos. Si ha creado o quiere realizar sus propios módulos, (como estos [[:Category:Módulos_complementarios|módulos complementarios]]), deberá reservarse un rango de ID aquí.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=ID 0 - 99999=&lt;br /&gt;
{{Flag en}}&lt;br /&gt;
Reserved for Dolibarr&#039;s internal modules.&lt;br /&gt;
&lt;br /&gt;
{{Flag fr}}&lt;br /&gt;
Réservé aux modules internes de Dolibarr.&lt;br /&gt;
&lt;br /&gt;
{{Flag sp}}&lt;br /&gt;
Reservado a los módulos internos de Dolibarr.&lt;br /&gt;
&lt;br /&gt;
=ID 100000 - 499999=&lt;br /&gt;
{{Flag en}} &lt;br /&gt;
Reserved area for editors in need for an ID range. You can edit this page to add your own range (take a range of 50 numbers only the first time, 1000 max per company)&lt;br /&gt;
&lt;br /&gt;
{{Flag fr}}Zone réservée aux éditeurs qui ont besoin d&#039;une plage d&#039;ID spécifiques. Vous pouvez modifier cette page pour réserver votre plage (limitée à 50 valeurs la première fois, 1000 maximum par société)&lt;br /&gt;
&lt;br /&gt;
{{Flag sp}}&lt;br /&gt;
Área reservada para los partners que necesiten un rango de ID. Puede modificar esta página para reservar su rango (limitado a 50 valores por editor)&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.png]] If you reserve more than 50, we may automatically change your reservation range without information and you may experience conflicts with other modules in a future, so please follow the rules !&lt;br /&gt;
&lt;br /&gt;
*ID 100000 - 100999: OpenThink (http://www.openthink.be)&lt;br /&gt;
*ID 101000 - 101999: NLTechno (https://www.nltechno.com)&lt;br /&gt;
*ID 102000 - 102999: Tiaris (http://www.tiaris.fr)&lt;br /&gt;
*ID 103000 - 103999: Open-concept.pro (http://www.open-concept.pro)&lt;br /&gt;
*ID 104000 - 104999: ATM Consulting (http://www.atm-consulting.fr)&lt;br /&gt;
*ID 105000 - 105999: GPC.solutions&lt;br /&gt;
*ID 106000 - 106999: PHPASSO&lt;br /&gt;
*ID 107000 - 107999: TecLib (http://www.teclib.com) / Auguria (http://www.auguria.net)&lt;br /&gt;
*ID 108000 - 108999: ETHICWEB&lt;br /&gt;
*ID 109000 - 109999: Oas services ([http://www.oas-services.fr https://www.oas-services.fr])&lt;br /&gt;
*ID 110000 - 110999: Librethic (https://librethic.io)&lt;br /&gt;
*ID 111000 - 111999: Asset IT (www.assetit.ch)&lt;br /&gt;
*ID 112000 - 112999: Aarboard AG (www.aarboard.ch)&lt;br /&gt;
*ID 113000 - 113999: Asilib - Alexandre Spangaro&lt;br /&gt;
*ID 114000 - 114999: Iceleaf OÜ&lt;br /&gt;
*ID 115000 - 115999: 2A2C Conseil - Cyril ZEKSER&lt;br /&gt;
*ID 116000 - 116999: Wolftec GmbH&lt;br /&gt;
*ID 117000 - 117999: Oscim (http://www.oscim.fr)&lt;br /&gt;
*ID 118000 - 118999: Oarces Web (dev.oarces.com)&lt;br /&gt;
*ID 119000 - 119999: Manuel Berrocal - Absolacom&lt;br /&gt;
*ID 120000 - 120999: Régis Houssin (http://www.inodbox.com)&lt;br /&gt;
*ID 121000 - 121999: Oscss - Shop&lt;br /&gt;
*ID 122000 - 122999: MrSof - la Nation du Web&lt;br /&gt;
*ID 123000 - 123999: Bruno Généré (webiseasy.org)&lt;br /&gt;
*ID 124000 - 124999: backbone internet service (www.backbone.co.at)&lt;br /&gt;
*ID 125000 - 125999: ProgSI (www.progsi.ma)&lt;br /&gt;
*ID 126000 - 126999: Catalanet&lt;br /&gt;
*ID 127000 - 127999: Virgilio Filho pt-BR Brasil (@dolibarr.br)&lt;br /&gt;
*ID 128000 - 128999: Nicolas Frappé France (www.sospc.info)&lt;br /&gt;
*ID 129000 - 129999: Adeo-Informatique&lt;br /&gt;
*ID 130000 - 130999: Technicks ICT (http://www.technicks.eu)&lt;br /&gt;
*ID 131000 - 131999: Joan Louis (itaca.fr)&lt;br /&gt;
*ID 132000 - 132999: Jean-Marie Arsac (https://azimut.fr)&lt;br /&gt;
*ID 133000 - 133999: Oriel Systems Ltd, UK. (www.orielsystems.com)&lt;br /&gt;
*ID 134000 - 134999: ALSOFT PVT. LTD. (https://www.alsoft.org)&lt;br /&gt;
*ID 135000 - 135999: Net-Logic (http://netlogic.fr)&lt;br /&gt;
*ID 140000 - 140999: Altairis (http://altairis.fr)&lt;br /&gt;
*ID 141000 - 141050: Projet2Team (https://www.projet2team.fr)&lt;br /&gt;
*ID 141051 - 141099: Elistair (http://elistair.com)&lt;br /&gt;
*ID 141100 - 141149: Blue Networks Technologies (https://www.blnt.fr)&lt;br /&gt;
*ID 141150 - 141199: Florian DUFOURG - France&lt;br /&gt;
*ID 142000 - 142049: ITANéA (https://www.itanea.fr)&lt;br /&gt;
*ID 142050 - 142099: ERP Consulting NZ ([https://www.erpconsulting.co.nz www.erpconsulting.co.nz])&lt;br /&gt;
*ID 150000 - 150999: Jeffinfo&lt;br /&gt;
*ID 160000 - 160999: Charles-François BENKE (http://www.patas-monkey.com)&lt;br /&gt;
*ID 161000 - 161999: Abbes Bahfir (http://dolipar.org)&lt;br /&gt;
*ID 162000 - 162999: Jacques Rébiscoul&lt;br /&gt;
*ID 163000 - 163999: Open-DSI (https://www.open-dsi.fr)&lt;br /&gt;
*ID 164000 - 164999: Pixelada S. Coop. And. (https://pixelada.org)&lt;br /&gt;
*ID 165000 - 165049: DovConnect&lt;br /&gt;
*ID 165050 - 165099: Mind Operated Systems (https://www.mosystems.biz)&lt;br /&gt;
*ID 165100 - 165150: SD-Formation (https://sdformation.fr)&lt;br /&gt;
*ID 170000 - 170999: TRIDENT CONSULTING LTD (www.tridentdxb.com)&lt;br /&gt;
*ID 171000 - 171999: LVSInformatique (www.lvsinformatique.com)&lt;br /&gt;
*ID 172000 - 172299: Ray Soft-Systems (https://www.ray-soft-systems.com)&lt;br /&gt;
*ID 172300 - 172349: Günter Lukas Consulting (https://gl.co.at)&lt;br /&gt;
*ID 172350 - 172399: MB Informatique (https://www.mb-informatique.fr)&lt;br /&gt;
*ID 172400 - 172449: Professional Structures Limited (https://pstructures.com)&lt;br /&gt;
*ID 172450 - 172699: IT-BS (https://www.it-bs.fr)&lt;br /&gt;
*ID 172700 - 172749: Indelog (https://www.indelog.fr)&lt;br /&gt;
*ID 172750 - 172799: NS-INFO90 (https://www.ns-info90.fr)&lt;br /&gt;
*ID 180000 - 180999: Triangle Ingénierie&lt;br /&gt;
*ID 181000 - 181999: TI Sin Problemas (https://www.tisinproblemas.com)&lt;br /&gt;
*ID 182000 - 182049: Chipserv Pawel Wlizlo (https://www.testware.it)&lt;br /&gt;
*ID 183000 - 183999: BB2A Anthony Berton (https://www.bb2a.fr)&lt;br /&gt;
*ID 190000 - 190999: Diciannove (http://19.coop)&lt;br /&gt;
*ID 191000 - 191999: Elonet (https://elonet.fr)&lt;br /&gt;
*ID 199000 - 199999: RFMS&lt;br /&gt;
*ID 200000 - 200999: Noxiome&lt;br /&gt;
*ID 201000 - 201999: Sasa Ostrouska (saxa)&lt;br /&gt;
*ID 202000 - 202999: Z-Application&lt;br /&gt;
*ID 203000 - 203099: Elidee - elidee.com&lt;br /&gt;
*ID 203100 - 203999: Garcia MICHEL (soamichel.fr)&lt;br /&gt;
*ID 204000 - 204999: Ari Elbaz elarifr - accedinfo.com&lt;br /&gt;
*ID 205000 - 205999: Kreiz IT&lt;br /&gt;
*ID 206000 - 206999: GBINFO (www.gbinfo.fr)&lt;br /&gt;
*ID 207000 - 207099: MacroProg (https://www.macroprog.com)&lt;br /&gt;
*ID 207100 - 207149: Reactiva Software&lt;br /&gt;
*ID 207150 - 207199: Ndejje University Water Research and Development Centre ([https://github.com/NDUWRDC/LIMS/])&lt;br /&gt;
*ID 207200 - 207299: Massaoud Bouzenad ([https://www.dzprod.net dzprod.net])&lt;br /&gt;
*ID 207300 - 207349: Ksar&lt;br /&gt;
*ID 207350 - 207399: Easylinux (www.easylinux.fr)&lt;br /&gt;
*ID 222000 - 222999:  dolibit  (https://www.dolibit.de)&lt;br /&gt;
*ID 230000 - 230049: Unareil (https://www.unareil.eu)&lt;br /&gt;
*ID 230050 - 230099: Lyra Network (https://www.lyra.com/)&lt;br /&gt;
*ID 230100 - 230149: Gheorghe Iftimi - CTW - RO&lt;br /&gt;
*ID 230150 - 230199: MEMA Machinery &amp;amp; Tools (https://www.mema.be)&lt;br /&gt;
*ID 230200 - 230249: Teleassist&lt;br /&gt;
*ID 230250 - 230299: Nh Developer&lt;br /&gt;
*ID 230300 - 230499: Chickenforce/code-chicken, IT Services Hahn (https://github.com/code-chicken [http://itservices-hahn.de/ https://itservices-hahn.de])&lt;br /&gt;
*ID 230500 - 230549: Hidup Consulting (https://consulting.hidup.io)&lt;br /&gt;
*ID 230550 - 230599 : CMR Conseil (https://www.weblockup.fr)&lt;br /&gt;
*ID 230600 - 230649 : aFreeMind Studio&lt;br /&gt;
*ID 230650 - 230699 : Unideal (https://www.uni-deal.com)&lt;br /&gt;
*ID 262700 - 262799: Scopen (https://www.scopen.fr)&lt;br /&gt;
*ID 274250 - 274299: Nerv Project (www.nerv-project.eu)&lt;br /&gt;
*ID 274300 - 274349: Knowhere Consulting S.L. (https://www.knowhere-consulting.eu)&lt;br /&gt;
*ID 274350: &#039;&#039;&#039;Free (take ranges of 50 only please, 1000 max per company)&#039;&#039;&#039;&lt;br /&gt;
*ID 320000 - 320999: Novus Studios (www.novusstudios.it)&lt;br /&gt;
*ID 321000 - 321999: AtooNet (http://www.atoo-net.com)&lt;br /&gt;
*ID 332000 - 332099: Gecka (https://gecka.nc)&lt;br /&gt;
*ID 332100 - 332149: Agence Milkshake (http://agencemilkshake.com)&lt;br /&gt;
*ID 332150 - 332199: Daniel Prowald IT – Service (https://prowald-it.de)&lt;br /&gt;
*ID 332200 - 332249: UNITICE (https://unitice.com)&lt;br /&gt;
*ID 332250 &#039;&#039;&#039;Free (take ranges of 50 only please, 1000 max per company)&#039;&#039;&#039;&lt;br /&gt;
*ID 330000 - 330049: XTEC Industries (www.xtec-ind.com)&lt;br /&gt;
*ID 330050 - 330099: 10100 S.R.L. - (www.10100.to)&lt;br /&gt;
*ID 330100 - 330149: AES Dana SRL (https://aes-dana.be)&lt;br /&gt;
*ID 330150 - 330199: Freshcore (https://www.freshcore.fr)&lt;br /&gt;
*ID 330200 - 399999: (take ranges of 50 only please, 1000 max per company)&lt;br /&gt;
*ID 400000 - 400999: 2byte.es (http://www.2byte.es)&lt;br /&gt;
*ID 401000 - 401999: B&amp;amp;D Informática&lt;br /&gt;
*ID 402000 - 402999: Marcos García de La Fuente (marcosgdf)&lt;br /&gt;
*ID 403000 - 403999: Sergibyte&lt;br /&gt;
*ID 404000 - 404999: Aikhan&lt;br /&gt;
*ID 405000 - 405999: AIME (http://www.aime.mx)&lt;br /&gt;
*ID 409000 - 409999: LliureTIC (www.lliuretic.cat)&lt;br /&gt;
*ID 420000 - 420099: BBS Concept&lt;br /&gt;
*ID 420100 - 420199: LeMousticProduction (www.lemousticproduction.info) -&amp;lt; module DoliRH&lt;br /&gt;
*ID 420200 - 421199: VatCheck (www.abnc.be)&lt;br /&gt;
*ID 422200 - 422999: Artaban (http://artaban.fr)&lt;br /&gt;
*ID 423000 - 423050: cyberesprit&lt;br /&gt;
*ID 423051 - 423099: R.Bossard&lt;br /&gt;
*ID 423100 - 423199: Joliciel (www.joliciel.fr)&lt;br /&gt;
*ID 424000 - 424049: A3sys - Mon-Dolibarr (http://www.mon-dolibarr.fr) by Philazerty&lt;br /&gt;
*ID 424050 - 424099: Pragma-tech (www.pragma-tech.fr)&lt;br /&gt;
*ID 424100 - 424149: Ohoo Solutions (http://www.ohoosolutions.com)&lt;br /&gt;
*ID 424150 - 424199: DAGARCAM Informática (https://www.dagarcam.com/)&lt;br /&gt;
*ID 424200 &#039;&#039;&#039;Free (take ranges of 50 only please, 1000 max per company)&#039;&#039;&#039;&lt;br /&gt;
*ID 425000 - 425999: Sébastien SERRE Thivinfo (www.thivinfo.com)&lt;br /&gt;
*ID 426000 - 426099: Arkesis-Solution&lt;br /&gt;
*ID 426100 - 426149: GetLandy (www.getlandy.com)&lt;br /&gt;
*ID 426150 - 426649: OOB Software&lt;br /&gt;
*ID 426650 - 426849: Soft-Task Serviços e Sistemas (www.soft-task.com.br)&lt;br /&gt;
*ID 426850 - 427000: Bruno Caldas (https://github.com/BCaldas)&lt;br /&gt;
*ID 427001 - 427999: Kevin GUERRIER (alias xcl.saian)&lt;br /&gt;
*ID 428000 - 428099: af83&lt;br /&gt;
*ID 428100 - 428199: Arnaud Serrut - Adalon&lt;br /&gt;
*ID 428200 &#039;&#039;&#039;Free (take ranges of 50 only please, 1000 max per company)&#039;&#039;&#039;&lt;br /&gt;
*ID 429000 - 429999: induslab&lt;br /&gt;
*ID 430000 - 430099: Mixity sprl (www.mixity.be)&lt;br /&gt;
*ID 430100 - 430199: sgiraud&lt;br /&gt;
*ID 430200 - 430299: Merlion TI (www.merlion-si.com.br)&lt;br /&gt;
*ID 430300 - 431299: Libre Expert (www.libre-expert.com)&lt;br /&gt;
*ID 431300 - 431399: ptibogxiv (www.ptibogxiv.net)&lt;br /&gt;
*ID 431400 - 431499: Befox (www.befox.fr)&lt;br /&gt;
*ID 431500 - 431599: rue Béjo (www.ruebejo.fr)&lt;br /&gt;
*ID 431600 - 431699: Avizzeo (www.avizzeo.com)&lt;br /&gt;
*ID 431700 - 432199: Multisistemas (www.multisistemas.com.sv)&lt;br /&gt;
*ID 432200 - 432399: Burbuja - Chile (www.burbuja.cl)&lt;br /&gt;
*ID 432400 - 433399: INOVEA CONSEIL (https://www.inovea-conseil.com)&lt;br /&gt;
*ID 433400 - 434399: Rachid HRICH - Maroc (HricH ServiceS.)&lt;br /&gt;
*ID 434400 - 435399: Lance Bleakley - LanceIT (www.lanceit.net)&lt;br /&gt;
*ID 436000 - 436099: SOWEBIO (www.soweb.io)&lt;br /&gt;
*ID 436100 - 436199: CAP-REL (www.cap-rel.fr)&lt;br /&gt;
*ID 436200 &#039;&#039;&#039;Free (take ranges of 50 only please at once, 1000 max per company)&#039;&#039;&#039;&lt;br /&gt;
*ID 436400 - 437399: Mohamed AHERDANE - Morocco - IT Consultant ( www.wave.ma )&lt;br /&gt;
*ID 437400 &#039;&#039;&#039;Free (take ranges of 50 only please at once, 1000 max per company)&#039;&#039;&#039;&lt;br /&gt;
*ID 438400 - 439399: Tetras Libre - France - Développement logiciels libres (www.tetras-libre.fr)&lt;br /&gt;
*ID 439400 - 440399: Dolibarr-pro - France - Développement Dolibarr (www.dolibarr-pro.com)&lt;br /&gt;
*ID 440400 - 441399: Quidlab Co., Ltd - Thailand - ( www.quidlab.com )&lt;br /&gt;
*ID 441400 - 442399: Ide@log - France - (https://www.idealog-info.net) - Laurent Leblanc&lt;br /&gt;
*ID 442400 - 443399: Valerio Bianchi (www.valeriobianchi.com)&lt;br /&gt;
*ID 443400 - 444399: delassalle - France - (www.delassalle.fr) - Joseph Delassalle&lt;br /&gt;
*ID 444400 - 445399: Webartis - Maroc - (www.webartis.net) - François Dry&lt;br /&gt;
*ID 445400 - 445499: SCOP Au-delà des nuages - France&lt;br /&gt;
*ID 446000 - 446999: iouston (http://www.iouston.com) - France - Julien Marchand&lt;br /&gt;
*ID 447000 - 447999: rSanjoSEO - Rafael San José Tovar (www.rsanjoseo.com) - Spain&lt;br /&gt;
*ID 448000 - 448999: Code 42 (www.code42.fr)&lt;br /&gt;
*ID 449000 - 449999: TakePOS (www.takepos.com)&lt;br /&gt;
*ID 450000 - 450999: Pierre ARDOIN&lt;br /&gt;
*ID 451000 - 451999: Éditeur depordi.fr&lt;br /&gt;
*ID 452000 - 452999: Dylan NAKONG&lt;br /&gt;
*ID 453000 - 453999: Menahd Ouchenir - France - menahd-ouchenir.com&lt;br /&gt;
*ID 454000 - 454999: Withheld - Canada&lt;br /&gt;
*ID 455000 - 455999: Gaëtan MAISON - Info Libre @ Dom - France (https://www.infolibreadom.com)&lt;br /&gt;
*ID 456000 - 456999: Laurent LEBLEU - B.L.C. - Blue Line Company - Lille - France (www.bluelinecompany.fr/dolibarr)&lt;br /&gt;
*ID 457000 - 457999: Sébastien BOUCHER&lt;br /&gt;
*ID 458000 - 458999: Lester HERNÁNDEZ - Argentina - (freelancerlrhd@gmail.com)&lt;br /&gt;
*ID 459000 - 459999: Infopen - France&lt;br /&gt;
*ID 460000 - 460050: torvista - Spain&lt;br /&gt;
*ID 461000 - 461999: MEGALOGI - Maroc (www.erpcloud.ma)&lt;br /&gt;
*ID 462000 - 462999: Making Digital (www.making-digital.fr) - France&lt;br /&gt;
*ID 463000 - 463999: linx s.r.l.s.&lt;br /&gt;
*ID 464000 - 464999: NimbleCubed Inc. (www.nimblecubed.com)&lt;br /&gt;
*ID 465000 - 465999: Artefacts - CourantAlternatif&lt;br /&gt;
*ID 466000 - 466999: CDM Consultores - (www.cdm.guru)&lt;br /&gt;
*ID 467000 - 467999: M71 Service GmbH - (www.m71-service.de)&lt;br /&gt;
*ID 468000 - 468049: Clément Segonzac - France (clement.segonzac@gmail.com)&lt;br /&gt;
*ID 468050 - 468099: Flavien Belli - France (https://github.com/Marshlyin || belliflaviencontactpro@gmail.com)&lt;br /&gt;
*ID 468100 - 468119: Chl (https://code.bugness.org/Dolibarr)&lt;br /&gt;
*ID 468120 - 468170: Commotron GmbH (https://www.commotron.com/)&lt;br /&gt;
*ID 468171 - 468174 &#039;&#039;&#039;Free (take ranges of 50 only please at once, 1000 max per company)&#039;&#039;&#039;&lt;br /&gt;
*ID 468175 - 468199: Gaëlle Rauffet - France (kiwiscan.net)&lt;br /&gt;
*ID 468200 - 468250: Paulo Oliveira - Brasil (paulorcdo@gmail.com)&lt;br /&gt;
*ID 468251 - 468270:  CD-Systems - France (https://www.cd-systems.fr)&lt;br /&gt;
*ID 468300 - 468349: Uvensys - Germany (https://uvensys.de)&lt;br /&gt;
*ID 468350 - 468399 : Laudeco - Belgium (http://github.com/laudeco)&lt;br /&gt;
*ID 468400 - 468449 : Alexis LAURIER - France (https://www.alexislaurier.fr)&lt;br /&gt;
*ID 468450 - 468499 : Mehdi Belkhayat - Maroc (https://opensi.ma)&lt;br /&gt;
*ID 468500 - 468599 : InvIT GmbH - Germany (https://invit.sh)&lt;br /&gt;
*ID 468600 - 468649 : Ricardo Sequeira - Portugal (https://ricardo-sequeira.com)&lt;br /&gt;
*ID 468650 - 468699 : J-IT - Belgique (https://www.j-it.be)&lt;br /&gt;
*ID 468700 - 468749 : Fidesio - France (https://www.fidesio.com/)&lt;br /&gt;
*ID 468750 - 468799 : Sgestion - Spain (http://www.sgestion.net/)&lt;br /&gt;
*ID 468800 - 468849 : Denis JULIEN - Brasil (matrinxa@free.fr)&lt;br /&gt;
*ID 468850 - 468900: Mmariko - Module GED - Effios&lt;br /&gt;
*ID 468901 - 468950: Maazou Amadou Abdoul aziz - Maroc (yaronfada@gmail.com)&lt;br /&gt;
*ID 468951 - 469000: Alexis LAURIER - France (https://www.alexislaurier.fr)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
=ID &amp;gt; 500000=&lt;br /&gt;
&lt;br /&gt;
This range can&#039;t be reserved. It is a common range. If you don&#039;t plan to distribute your module, you can use an ID in this range with no need to reserve it.&lt;br /&gt;
&lt;br /&gt;
{{Flag en}}&lt;br /&gt;
If you don&#039;t already have reserved ids and need some, please don&#039;t use hazardous number and use a number higher than 500000, but it is better to ask a wiki account, and reserve your own range by editing the  100000 - 499999 range (50 ids at once, 1000 ids maximum per partner).&lt;br /&gt;
&lt;br /&gt;
{{Flag fr}}&lt;br /&gt;
Si vous n&#039;avez pas de numéros réservés et en avez besoin, n&#039;utilisez pas de chiffres au hasard et utilisez une valeur supérieure à 500000, toutefois, il est préférable d&#039;obtenir un compte wiki, et  réserver vous-même votre plage en ajoutant votre entrée dans la zone 100000 - 499999 (par lot de 50 d&#039;abord, pas plus de 1000 numéros par partenaire).&lt;br /&gt;
&lt;br /&gt;
{{Flag sp}}&lt;br /&gt;
Si no dispone de número reservado y necesita, no use cifras redondeadas y usa un valor superior a 500000. Si tiene una cuenta wiki, puede reservarse usted mismo sus id añadiendo su entrada en la zona 100000 - 499999 (no más de 1000 id por partner).&lt;/div&gt;</summary>
		<author><name>ALSOFT</name></author>
	</entry>
</feed>