Extrafields: Difference between revisions

From Dolibarr ERP CRM Wiki
Jump to navigation Jump to search
(Document Object Link extrafield filter syntax (#37610))
Tag: 2017 source edit
 
(19 intermediate revisions by 10 users not shown)
Line 1: Line 1:
<!-- BEGIN origin interlang links -->
<!-- You can edit this section but do NOT remove these comments
    Links below will be automatically replicated on translated pages by PolyglotBot -->
[[zh:附加字段]]
[[fr:Champs_personnalises]]
<!-- END interlang links -->
{{TemplateDocDevEn}}
{{TemplateDocDevEn}}
= Extrafields =


Extrafields allow to add others datas to Dolibarr standard database schema. Introduced in version 3.2, extrafields are now implemented in businesses object :
=Extrafields=
* Thirdparties & contacts
Extrafields allow to add others datas to Dolibarr standard database schema. Introduced in version 3.2, extrafields are now implemented in most business objects<span> </span>:
* Users
* Events
* Customer Invoices
* Proposal
* Products & services
* Member & member type
* Orders
* Projects & project tasks (since 3.4)


== Technical implementation ==
*Thirdparties & contacts
*Users
*Events
*Proposal
*Customer Invoices
*Orders
*Supplier Proposal
*Supplier Invoices
*Supplier Orders
*Products & services
*Member & member type
*Projects & project tasks (since 3.4)
*Categories
*Expense Report


Each object have his table in database to store values of extrafields.
=Technical implementation=
 
Each object has its table in database to store values of extrafields.
 
==Datatables extrafield tables models==


== Datatables extrafield tables models ==
   llx_''BaseTableNAme''_extrafields
   llx_''BaseTableNAme''_extrafields
   rowid                    integer AUTO_INCREMENT PRIMARY KEY,
   rowid                    integer AUTO_INCREMENT PRIMARY KEY,
Line 24: Line 38:
   import_key                varchar(14)
   import_key                varchar(14)


== Load class for extrafields ==
 
An example of mysql definition file for extrafields implementation on an object<span> </span>:
 
  create table llx_place_room_extrafields
  (
    rowid                    integer AUTO_INCREMENT PRIMARY KEY,
    tms                      timestamp,
    fk_object                integer NOT NULL,
    import_key                varchar(14)                          -- import key
  ) ENGINE=innodb;
 
The "Unique" property of extrafield create a `UNIQUE INDEX` on this field, forcing objects to have a unique value for their extrafield (two objects cannot have the same value).
 
=Usage=
 
==Object Link filters==
 
An Object Link extrafield can filter the objects shown in its selection list. The descriptor format is:
 
<syntaxhighlight lang="text">
ObjectName:classPath:<showempty>:(field:operator:value)
</syntaxhighlight>
 
For example, to show objects whose status is 1:
 
<syntaxhighlight lang="text">
ObjectName:classPath:1:(status:=:1)
</syntaxhighlight>
 
The segments are:
 
* <code>ObjectName</code>: the Dolibarr object name to link to.
* <code>classPath</code>: the path to the PHP class for that object.
* <code>&lt;showempty&gt;</code>: use 0 or 1 in this slot. Current code has a nuance: extrafield rendering derives whether to offer an empty choice from the field's Required and default-value settings, while the link-field parser treats a numeric third segment as its add-create-button flag. Do not rely on this slot to override the empty-choice setting.
* <code>(field:operator:value)</code>: a filter in Dolibarr's Universal Filter Syntax. Keep it in parentheses, with the field name, operator, and value separated by colons.
 
Supported operators are <code>=</code>, <code>!=</code>, <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code>, <code>in</code>, <code>notin</code>, <code>like</code>, <code>notlike</code>, <code>is</code>, and <code>isnot</code>. For example, <code>(status:=:1)</code> means <code>status = 1</code>. Criteria can be combined with <code>AND</code> or <code>OR</code>.
 
===Placeholders and object context===
 
* <code>$ID$</code> is the ID of the current object. For an extrafield on an invoice line, it is the line ID, not the parent invoice ID or its third party.
* <code>$MODE$</code> is replaced with the current display mode, such as list or view.
* <code>$ENTITY$</code> is replaced with the current entity ID.
* <code>$SEL$</code> can represent <code>SELECT</code> in a subquery only when the PHP global <code>$dolibarr_allow_unsecured_select_in_extrafields_filter</code> is enabled. This permits unsecured SELECT subqueries and is disabled unless explicitly enabled. Enabling it is an administrator security decision; a subquery should not be presented as the default workaround.
 
The issue's example, <code>Contact:contact/class/contact.class.php:*:fk_soc=:__THIRDPARTY_ID__</code>, is malformed: the filter needs parentheses and the <code>field:operator:value</code> format. A syntactically corrected form using the supported current-object placeholder is:
 
<syntaxhighlight lang="text">
Contact:contact/class/contact.class.php:1:(fk_soc:=:$ID$)
</syntaxhighlight>
 
On an invoice-line extrafield, however, <code>$ID$</code> is the line ID, so this does not filter contacts by the parent invoice's third party. <code>__THIRDPARTY_ID__</code> is a template substitution token, not a placeholder supported by this extrafield-filter path. The parent third party is not directly exposed to this filter.
 
==Load class for extrafields==
To use extrafields all pages need include  
To use extrafields all pages need include  
<source lang="php">
<syntaxhighlight lang="PHP">
require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
</source>
</syntaxhighlight>


== Load extrafield array in object ==
==Load extrafield array in object==
<source lang="php">
<syntaxhighlight lang="PHP">
$extrafields = new ExtraFields($db);
$extrafields = new ExtraFields($db);
$extralabels=$extrafields->fetch_name_optionals_label($object->table_element);
$extralabels=$extrafields->fetch_name_optionals_label($object->table_element);
</source>
</syntaxhighlight>


$extralabels will be an array with code and label of extrafields.
$extralabels will be an array with code and label of extrafields.
This code must be placed into the class for example into the function "write_file".


== Load extrafield into object ==
==Load extrafield into object==


Extrafields are loaded in $object->array_options array.
Extrafields are loaded in $object->array_options array.


<source lang="php">
<syntaxhighlight lang="PHP">
$object->fetch($rowid);
$object->fetch($rowid);
$object->fetch_optionals($rowid,$extralabels);
$object->fetch_optionals($rowid,$extralabels);
</source>
</syntaxhighlight>
 
This code must be placed just after the above.
 
==Display extrafield value into PDF or HTML==
After load extrafields
 
HTML Exemple
<syntaxhighlight lang="PHP">
print $object->array_options ['options_XXX'];
</syntaxhighlight>
Where XXX is the code of the extrafields
 
PDF example
<syntaxhighlight lang="PHP">
$pdf->MultiCell (0,5, $outputlangs->convToOutputCharset($object->array_options ['options_XXX']),0,'L'); )
</syntaxhighlight>
Where XXX is the code of the extrafields
 
A dedicated page to show how to integrate extrafileds into PDF can be found there<span> </span>: [[Add Extrafields on PDF Models]]
 
==Display extrafield value of lines into PDF or HTML==
After load extrafields
 
HTML Exemple
<syntaxhighlight lang="PHP">
print $object->lines[$i]->array_options['options_XXX'];
</syntaxhighlight>
Where XXX is the code of the extrafields


== Before call $object->create() or $object->update() ==
PDF example
<syntaxhighlight lang="PHP">
$pdf->MultiCell (0,5, $outputlangs->convToOutputCharset($object->lines[$i]->array_options['options_XXX']),0,'L');
</syntaxhighlight>
Where XXX is the code of the extrafields


Values of extrafields sent by form need to be retrieve. For do that, use this method :
 
<source lang="php">
==How to change the labels of the columns when using models (propals, etc.)==
In the PHP code of the model you can change the labels of your extrafield by changing into the function named "_tableau(...)"
 
==Before call $object->create() or $object->update()==
 
Values of extrafields sent by form need to be retrieve. For doing that, use this method<span> </span>:
<syntaxhighlight lang="PHP">
$ret = $extrafields->setOptionalsFromPost($extralabels,$object);
$ret = $extrafields->setOptionalsFromPost($extralabels,$object);
</source>
</syntaxhighlight>


==Inside edit page to display extrafields==


== Inside edit page to display extrafields ==


 
<syntaxhighlight lang="PHP">
<source lang="php">
$reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action);    // Note that $action and $object may have been modified by hook
$reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action);    // Note that $action and $object may have been modified by hook
if (empty($reshook) && ! empty($extrafields->attribute_label))
if (empty($reshook) && ! empty($extrafields->attribute_label))
Line 64: Line 169:
       print $object->showOptionals($extrafields,'edit');
       print $object->showOptionals($extrafields,'edit');
}
}
</source>
</syntaxhighlight>


== Inside view page to display extrafields ==
==Inside view page to display extrafields==


<source lang="php">
<syntaxhighlight lang="PHP">
$reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$act,$action);    // Note that $action and $object may have been modified by hook
$reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action);    // Note that $action and $object may have been modified by hook
if (empty($reshook) && ! empty($extrafields->attribute_label))
if (empty($reshook) && ! empty($extrafields->attribute_label))
{
{
       print $object->showOptionals($extrafields);
       print $object->showOptionals($extrafields);
}
}
</source>
</syntaxhighlight>


== After fetch method of this object class ==
==After fetch method of this object class==
<source lang="php">
<syntaxhighlight lang="PHP">
require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php');
require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php');
$extrafields=new ExtraFields($this->db);
$extrafields=new ExtraFields($this->db);
Line 84: Line 189:
$this->fetch_optionals($this->id,$extralabels);
$this->fetch_optionals($this->id,$extralabels);
}
}
</source>
</syntaxhighlight>


==After Update method of this object class :==
==After Update method of this object class<span> </span>:==
<source lang="php">
<syntaxhighlight lang="PHP">
// Actions on extra fields (by external module or standard code)
// Actions on extra fields (by external module or standard code)
// FIXME le hook fait double emploi avec le trigger !!
// FIXME le hook fait double emploi avec le trigger !!
Line 105: Line 210:
}
}
else if ($reshook < 0) $error++;
else if ($reshook < 0) $error++;
</source>
</syntaxhighlight>


== After delete method of this object class ==
==After delete method of this object class==
<source lang="php">
<syntaxhighlight lang="PHP">
// Removed extrafields
// Removed extrafields
if (! $error)
if (! $error)
Line 122: Line 227:
   }
   }
}
}
</source>
</syntaxhighlight>


==Admin pages ==
==Admin pages==
<source lang="php">
<syntaxhighlight lang="PHP">
$elementtype='facture'; //Must be the $table_element of the class that manage extrafield
$elementtype='facture'; //Must be the $table_element of the class that manage extrafield
</source>
</syntaxhighlight>


==Repair Database ==
=Repair Database=
Search and find definition of $listofmodulesextra add the new extrafield declaration
Search and find definition of $listofmodulesextra add the new extrafield declaration
<source lang="php">
<syntaxhighlight lang="PHP">
$listofmodulesextra=array('societe'=>'societe','adherent'=>'adherent','product'=>'product',
$listofmodulesextra=array('societe'=>'societe','adherent'=>'adherent','product'=>'product',
'socpeople'=>'socpeople', 'commande'=>'commande', 'facture'=>'facture',
'socpeople'=>'socpeople', 'commande'=>'commande', 'facture'=>'facture',
'commande_fournisseur'=>'commande_fournisseur', 'actioncomm'=>'actioncomm',
'commande_fournisseur'=>'commande_fournisseur', 'actioncomm'=>'actioncomm',
'adherent_type'=>'adherent_type','user'=>'user','projet'=>'projet', 'projet_task'=>'projet_task');
'adherent_type'=>'adherent_type','user'=>'user','projet'=>'projet', 'projet_task'=>'projet_task');
</source>
</syntaxhighlight>
 
=Related videos=
 
Extrafields:
(vocal in french but subtitles are available and review in this language)
 
<youtube width="200" height="180">Eex2YXxToS0</youtube>
<youtube width="200" height="180">QQnyoUGsN1c</youtube>
<youtube width="200" height="180">md6JHbd8o_0</youtube>

Latest revision as of 12:14, 26 October 2026


Extrafields

Extrafields allow to add others datas to Dolibarr standard database schema. Introduced in version 3.2, extrafields are now implemented in most business objects :

  • Thirdparties & contacts
  • Users
  • Events
  • Proposal
  • Customer Invoices
  • Orders
  • Supplier Proposal
  • Supplier Invoices
  • Supplier Orders
  • Products & services
  • Member & member type
  • Projects & project tasks (since 3.4)
  • Categories
  • Expense Report

Technical implementation

Each object has its table in database to store values of extrafields.

Datatables extrafield tables models

 llx_BaseTableNAme_extrafields
 rowid                     integer AUTO_INCREMENT PRIMARY KEY,
 tms                       timestamp,
 fk_object                 integer NOT NULL,
 import_key                varchar(14)


An example of mysql definition file for extrafields implementation on an object :

 create table llx_place_room_extrafields
 (
   rowid                     integer AUTO_INCREMENT PRIMARY KEY,
   tms                       timestamp,
   fk_object                 integer NOT NULL,
   import_key                varchar(14)                          		-- import key
 ) ENGINE=innodb;

The "Unique" property of extrafield create a `UNIQUE INDEX` on this field, forcing objects to have a unique value for their extrafield (two objects cannot have the same value).

Usage

Object Link filters

An Object Link extrafield can filter the objects shown in its selection list. The descriptor format is:

ObjectName:classPath:<showempty>:(field:operator:value)

For example, to show objects whose status is 1:

ObjectName:classPath:1:(status:=:1)

The segments are:

  • ObjectName: the Dolibarr object name to link to.
  • classPath: the path to the PHP class for that object.
  • <showempty>: use 0 or 1 in this slot. Current code has a nuance: extrafield rendering derives whether to offer an empty choice from the field's Required and default-value settings, while the link-field parser treats a numeric third segment as its add-create-button flag. Do not rely on this slot to override the empty-choice setting.
  • (field:operator:value): a filter in Dolibarr's Universal Filter Syntax. Keep it in parentheses, with the field name, operator, and value separated by colons.

Supported operators are =, !=, <, >, <=, >=, in, notin, like, notlike, is, and isnot. For example, (status:=:1) means status = 1. Criteria can be combined with AND or OR.

Placeholders and object context

  • $ID$ is the ID of the current object. For an extrafield on an invoice line, it is the line ID, not the parent invoice ID or its third party.
  • $MODE$ is replaced with the current display mode, such as list or view.
  • $ENTITY$ is replaced with the current entity ID.
  • $SEL$ can represent SELECT in a subquery only when the PHP global $dolibarr_allow_unsecured_select_in_extrafields_filter is enabled. This permits unsecured SELECT subqueries and is disabled unless explicitly enabled. Enabling it is an administrator security decision; a subquery should not be presented as the default workaround.

The issue's example, Contact:contact/class/contact.class.php:*:fk_soc=:__THIRDPARTY_ID__, is malformed: the filter needs parentheses and the field:operator:value format. A syntactically corrected form using the supported current-object placeholder is:

Contact:contact/class/contact.class.php:1:(fk_soc:=:$ID$)

On an invoice-line extrafield, however, $ID$ is the line ID, so this does not filter contacts by the parent invoice's third party. __THIRDPARTY_ID__ is a template substitution token, not a placeholder supported by this extrafield-filter path. The parent third party is not directly exposed to this filter.

Load class for extrafields

To use extrafields all pages need include

require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';

Load extrafield array in object

$extrafields = new ExtraFields($db);
$extralabels=$extrafields->fetch_name_optionals_label($object->table_element);

$extralabels will be an array with code and label of extrafields. This code must be placed into the class for example into the function "write_file".

Load extrafield into object

Extrafields are loaded in $object->array_options array.

$object->fetch($rowid);
$object->fetch_optionals($rowid,$extralabels);

This code must be placed just after the above.

Display extrafield value into PDF or HTML

After load extrafields

HTML Exemple

print $object->array_options ['options_XXX'];

Where XXX is the code of the extrafields

PDF example

$pdf->MultiCell (0,5, $outputlangs->convToOutputCharset($object->array_options ['options_XXX']),0,'L'); )

Where XXX is the code of the extrafields

A dedicated page to show how to integrate extrafileds into PDF can be found there : Add Extrafields on PDF Models

Display extrafield value of lines into PDF or HTML

After load extrafields

HTML Exemple

print $object->lines[$i]->array_options['options_XXX'];

Where XXX is the code of the extrafields

PDF example

$pdf->MultiCell (0,5, $outputlangs->convToOutputCharset($object->lines[$i]->array_options['options_XXX']),0,'L');

Where XXX is the code of the extrafields


How to change the labels of the columns when using models (propals, etc.)

In the PHP code of the model you can change the labels of your extrafield by changing into the function named "_tableau(...)"

Before call $object->create() or $object->update()

Values of extrafields sent by form need to be retrieve. For doing that, use this method :

$ret = $extrafields->setOptionalsFromPost($extralabels,$object);

Inside edit page to display extrafields

$reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action);    // Note that $action and $object may have been modified by hook
if (empty($reshook) && ! empty($extrafields->attribute_label))
{
      print $object->showOptionals($extrafields,'edit');
}

Inside view page to display extrafields

$reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action);    // Note that $action and $object may have been modified by hook
if (empty($reshook) && ! empty($extrafields->attribute_label))
{
      print $object->showOptionals($extrafields);
}

After fetch method of this object class

require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php');
$extrafields=new ExtraFields($this->db);
$extralabels=$extrafields->fetch_name_optionals_label($this->table_element,true);
if (count($extralabels)>0) {
	$this->fetch_optionals($this->id,$extralabels);
}

After Update method of this object class :

// Actions on extra fields (by external module or standard code)
// FIXME le hook fait double emploi avec le trigger !!
$hookmanager->initHooks(array('HookModuleNamedao'));
$parameters=array('socid'=>$this->id);
$reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
if (empty($reshook))
{
	if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
	{
            $result=$this->insertExtraFields();
            if ($result < 0)
            {
            	$error++;
            }
        }
}
else if ($reshook < 0) $error++;

After delete method of this object class

// Removed extrafields
if (! $error)
{
      if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
      {
      $result=$this->deleteExtraFields();
      if ($result < 0)
      {
        $error++;
        dol_syslog(get_class($this)."::delete erreur ".$errorflag." ".$this->error, LOG_ERR);
      }
   }
}

Admin pages

$elementtype='facture'; //Must be the $table_element of the class that manage extrafield

Repair Database

Search and find definition of $listofmodulesextra add the new extrafield declaration

$listofmodulesextra=array('societe'=>'societe','adherent'=>'adherent','product'=>'product',
			'socpeople'=>'socpeople', 'commande'=>'commande', 'facture'=>'facture',
			'commande_fournisseur'=>'commande_fournisseur', 'actioncomm'=>'actioncomm',
			'adherent_type'=>'adherent_type','user'=>'user','projet'=>'projet', 'projet_task'=>'projet_task');

Related videos

Extrafields: (vocal in french but subtitles are available and review in this language)