Module CustomFields Dev

From Dolibarr ERP CRM Wiki
Revision as of 13:42, 29 August 2012 by Lrq3000 (talk | contribs) (Created page with "Category:Complementary modules Category:CustomFields {{TemplateDocUser}} {{TemplateDocDevEn}} {{TemplateModEN}} {{BasculeDevUserEn| name=CustomFields| num=8500| devdoc=Th...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
CustomFields
Numero/ID of module 8500
User doc. of module This page
Developer doc. of module This page

These notes are aimed to developpers that want to extend the functionnalities of the module or want to use it for extreme cases. This is not meant to guide implementers on how to implement and configure the module (see the related chapter for that).

Principles

CustomFields is simply a wrapper for SQL databases.

The module is based on SQL to manage the fields and most of the stuff. It uses and understand standard SQL.

The main principle of CustomFields is:

  • one SQL field = one Dolibarr field
  • one SQL type = one way to show and edit the field in Dolibarr

Goals

This module was made to provide an easy way to manage custom sql fields, not only for users and implementers, but also for developpers to use in their own module:

  • by easily adding the support of custom fields for your own module by using this module;
  • by reusing custom fields from another module in your own module;
  • by managing sql fields in your own module by using the CustomFields class (which will take care of everything from printing, editing to PDF/ODT templating).

So this module is not only an auxiliary of other modules, but it can also be the core part of your own module by using it as your SQL query class for fields.

SQL structure

A CustomFields table needs to respect three parameters that never change:

  • table's name (format: llx_*dolibarrmodule*_customfields where *dolibarrmodule* = table_element in conf_customfields.lib.php)
  • first column: rowid, which is the primary key for each field
  • second column: fk_*dolibarrmodule* which is the foreign key that links every customfields record to the Dolibarr's module that is associated (invoice, order, etc...).

Apart from the table's name and the first two special columns, every other columns are just standard sql columns that you can freely create, edit or delete as you want, from the module's administration page or from a third-party SQL management tool (such as phpMyAdmin).

You can also create more complex sql fields: constraints, foreign keys, transformations, other sql types, etc...).

Then the module will try to manage the sql fields you manually created the best it can:

  • by printing appropriate input fields in the Dolibarr gui interface.
  • by providing the developper an easy access to these fields in php (eg: $customfields->cf_myfield or $object->customfields->cf_myfield) for any use, including PDF templates and ODT templates, or in any php script (so that you can use these fields in your own module).

SQL Indexes

The module automatically adds an index on the primary key and foreign key (first and second columns).

To further optimize the performances of your database, and particularly the customfields tables, you may want to manually add indexes based on usage.

Also, you may add indexes on remote tables used by constrained fields, which could optimize even more the performances since constrained fields have the worst performance drawback for CustomFields.

Architecture

Here is a full list of the CustomFields packaged files with a short description (for a more in-depth view just crawl the source files, they are full of comments):

Core files

files that are necessary for the CustomFields to work, they contains the core functions

  • /customfields/admin/customfields.php --- Administrator's configuration panel : this is where you create and manage the custom fields definitions
  • /customfields/class/actions_customfields.class.php --- Hooks class : used to hook into Dolibarr core modules without altering any core file (can be used to hook into your own modules too)
  • /customfields/class/customfields.class.php --- Core class : every database action is made here in this class. You can find some printing functions because they are very generic.
  • /customfields/conf/conf_customfields.lib.php --- Configuration file : contains the main configurable variables to adapt CustomFields to your needs or to expand its support to other modules and more native sql types.
  • /customfields/conf/conf_customfields_func.lib.php --- Auxiliary functions library to read and manage config variables
  • /customfields/core/modules/modCustomFields.class.php --- Dolibarr's module definition file : this is a core file necessary for Dolibarr to recognize the module and to declare the hooks to Dolibarr (but it does not store anything else than meta-informations).
  • /customfields/core/substitutions/functions_customfields.lib.php --- CustomFields substitution class for ODT generation : necessary to support customfields tags in ODT files
  • /customfields/core/triggers/interface_50_modCustomFields_SaveFields.class.php --- Core triggers file : this is where the actions on records are managed. This is an interface between other modules and CustomFields management. This is where you must add the actions of other modules you'd want to support (generic customfields triggers actions are provided so you just have to basically do a copy/paste, see the related chapter). Also, if CustomFields are shown in the forms but cannot be modified nor saved, then probably this trigger file is not detected by Dolibarr (maybe you can try to lower the number 50 to raise the priority?).
  • /customfields/fields/customfields_fields_extend.lib.php --- Overloading functions library with users functions
  • /customfields/langs/code_CODE/customfields.lang --- Core language file : this is where you can translate the admin config panel (data types names, labels, descriptions, etc.)
  • /customfields/langs/code_CODE/customfields-user.lang --- User defined language file : this is where you can store the labels and values of your custom fields (see the related chapter)
  • /customfields/lib/customfields_aux.lib.php --- Simplifier library to easily use CustomFields class to populate an $object with custom fields datas (Facade design pattern)
  • /customfields/lib/customfields_printforms.lib.php --- Core printing library for records : contains only printing functions, there's no really core functions but it permits to manage the printing of the custom fields records and their editing
  • /customfields/sql/*.sql --- Unused (the tables are created directly via a function in the customfields.class.php)


PDFTest module

optional module to append a page listing all custom fields values on newly generated PDF documents. To be used to test if custom fields are working correctly before making one's own template.

  • /customfieldspdftest/class/actions_customfieldspdftest.class.php --- Main functions library and hooks class, to hook onto pdf generation. Contains the PDFTest functions.
  • /customfieldspdftest/core/modules/modCustomFieldsPDFTest.class.php --- Module descriptor for Dolibarr

How to add the support of a new module

There are two cases: either the module already implements hooks, and you just have to configure CustomFields to support it, or either the module does not implements hooks nor triggers.

This chapter will guide you through the steps to make any module supported by CustomFields (be it a Dolibarr core module or your own module).

Preliminary test

Implementing the support of CustomFields in the module

If there is a module you want to implement the support of CustomFields, but does not yet has the required components, here is a guide on how to implement these components.

Hooks

First you should be familiar with the way that hooks are implemented in modules. If you don't, please first read the hooks documentation.

// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array
include_once(DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php');
$hookmanager=new HookManager($db);
$hookmanager->initHooks(array('yourmodule'));

print '</td></tr>';

// Other attributes
$parameters=array('colspan' => ' colspan="3"');
$reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action);    // Note that $action and $object may have been modified by hook

print '</table>';


Triggers

Needs at least 3 triggers: - on creation of object - eg: YOURMODULE_CREATE - on creation of lines - eg: YOURMODULELINE_INSERT (optional, only if your module has product lines) - on update of lines - eg: YOURMODULELINE_UPDATE (optional, only if your module has product lines)

For more informations about how to implement triggers in your module, please read the triggers wiki page.

Hook name: formObjectOptions

Note: you need to supply the sql id of the newly created object before calling the trigger.

Eg:

$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."yourmodule_table_element");

// Appel des triggers
include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
$interface=new Interfaces($this->db);
$result=$interface->run_triggers('YOURMODULE_CREATE',$this,$user,$langs,$conf);
if ($result < 0) {
    $error++; $this->errors=$interface->errors;
}
// Fin appel triggers

For lines, you should anyway use the product lines template files: htdocs/core/tpl/freeproductline_edit.tpl.php

If you don't, you can still manually implement the required hooks, what is required is that you supply $line (which is the current line object being processed) in the $parameters array:

$parameters=array('line'=>$line,'fk_parent_line'=>$line->fk_parent_line);

echo $hookmanager->executeHooks('formEditProductOptions',$parameters,$this,$action);

Hooks names:

  • formEditProductOptions
  • formViewProductOptions

Configuring CustomFields to support the module

0/ Preliminary work You will need 3 things here: the module's table name, the module's context and the module's trigger action(s).

To get these informations, you can take a look inside the code of the module's files you want to implement:

or you can get it by printing it in the /htdocs/customfields/class/actions_customfields.class.php by adding print_r($parameters) and search for $parameters->context

  • module's trigger actions: search for "run_triggers(" or take a look at the wiki: http://wiki.dolibarr.org/index.php/Triggers#List_of_known_triggers_actions
  • module's table name: either find it by yourself in the database (looks like llx_themodulename) or by printing it in actions_customfields.class.php by adding print_r($parameters) and search for $parameters->table_element

1/ With these values, edit the config file (/htdocs/customfields/conf/conf_customfields.lib.php), particularly the $modulesarray and $triggersarray variables:

A- Add the context and module's table name in the modulesarray: $modulesarray = array("invoicecard"=>"facture",

                                           "propalcard"=>"propal",
                                           "productcard"=>"product",
                                           "ordercard"=>"commande",

"yourmodulecontext"=>"yourmoduletablename"); // Edit me to add the support of another module - NOTE: Lowercase only!

B- Add the triggers (there can be several triggers): $triggersarray = array("order_create"=>"commande", "yourmoduletriggeraction1"=>"yourmoduletablename", "yourmoduletriggeraction2"=>"yourmoduletablename");

Note: generally you will be looking to implement the _CREATE and _PREBUILDDOC actions.

Done, now the module should be fully supported! If that's not the case, try the following:

- If you can save and create but cannot generate the document, see the 4th step for implementing the PREBUILDDOC trigger. - If you can neither save nor create the fields, you just see them but changes are not committed when submitting, try to implement the support via the old way (which should work all the time for any case).

TO DO

To Do:

  • Add a confirmation when deleting a custom field (because user's datas are lost forever!).

Should do :

  • Checkbox (multiple checkboxes, one for each possible value) and multiselect (big select and can use SHIFT to multiselect) (store in XML file) (but impossible with constrained fields, can't store multiple foreign keys ids in one single sql field, but would work for other types like enum)

use fieldset, input checkbox and label for, eg:

   <fieldset><legend><label for="cf_productslist"> $langs->trans('cf_productslist')</label></legend>
   <input type="checkbox" name="cf_productslist_choice1" value="1" id="cf_productslist_choice1" /><label for="cf_productslist_choice1"> $langs->trans('cf_productslist_choice1')</label>
<input type="checkbox" name="cf_productslist_choice2" value="1" id="cf_productslist_choice2" /><label for="cf_productslist_choice2"> $langs->trans('cf_productslist_choice2')</label>
etc... </fieldset>
  • Refactor the trigger array: merge it with the modulesarray (along with a new way to specify which customfields trigger action a trigger should correspond, eg: 'linebill_insert'=>'customfields_create').
  • Add a javascript options values generator for the enum type (a hidden input that would be shown only when DropdownBox type is selected and that would permit to add options by clicking a plus button).

Known bugs :

  • in product and service modules, if you edit a field, the proposals and other fields below won't be shown, you need to refresh the page. This problem resides in Dolibarr I think (since we are simply using a hook).

Never/Maybe one day :

  • Add Upload field type (almost useless since we can attach files).
  • Add support for repeatable (predefined) invoices (the way it is currently managed makes it very difficult to manage this without making a big exception, adding specific functions in customfields modules that would not at all will be reusable anywhere else, when customfields has been designed to be as generic as possible to support any module and any version of dolibarr, because it's managed by a totally different table while it's still managed by the same module, CustomFields work with the paradigm: one module, one table).
  • AJAX? (but only optional, because else it won't work for mobile phones and tablets)
  • Extend meta-data storage using XML files?
  • Add an AJAX select box for constained values : when a constrained type is selected and a table is selected, a hidden select box would show up with the list of the fields of this table to choose the values that will be printed as the values for this customfield (eg: for table llx_users you could select the "nom" field and then it would automatically prepend "nom_" to the field's name).
  • A way to reorder the fields without deleting/recreating (add a third special column after fk_module, or in XML meta-data file?)