Changes

m
no edit summary
Line 7: Line 7:  
devdoc=This page|
 
devdoc=This page|
 
userdoc=[[Module_CustomFields]]|}}
 
userdoc=[[Module_CustomFields]]|}}
[[Category:FAQ EN]]
      
These notes are aimed to developpers who want to extend the functionnalities of the module or want to use it for extreme cases.
 
These notes are aimed to developpers who want to extend the functionnalities of the module or want to use it for extreme cases.
Line 13: Line 12:     
If you are an implementer and just want to use CustomFields with its normal functions, you can read the [[Module_CustomFields|user documentation of CustomFields]].
 
If you are an implementer and just want to use CustomFields with its normal functions, you can read the [[Module_CustomFields|user documentation of CustomFields]].
 +
 +
You can also jump directly to [[Module_CustomFields_Cases]] wiki page for a collection of practical examples.
    
= Principles =
 
= Principles =
Line 91: Line 92:  
The other advantage is that php objects can directly be encoded into JSON without any preprocessing, and can then as straightly be decoded from JSON back into a php object.
 
The other advantage is that php objects can directly be encoded into JSON without any preprocessing, and can then as straightly be decoded from JSON back into a php object.
   −
A simple mean to encode and decode back an object into and from a storage place was the main requirement, and JSON (+ JSON libraries for PHP) meet this criteria.
+
A simple mean to encode and decode back an object into and from a storage place, as well as allow users to easily add/remove extra options were the main requirement, and JSON (+ JSON libraries for PHP) meet this criteria.
 +
 
 +
However, note that the extra options are now encoded as an associative array, so as to avoid any ambiguities (there's no associative array in JSON, they are converted to objects).
    
== Implementation of JSON ==
 
== Implementation of JSON ==
Line 121: Line 124:  
Eg:
 
Eg:
 
<source lang="php">
 
<source lang="php">
$extra = new stdClass(); // instanciating an empty object
+
$extra = array(); // $extra should always be an associative array, it's no longer an object
$extra->myproperty = 'Anything I want here'; // set a property/extra option like this
+
$extra['myproperty'] = 'Anything I want here'; // set a property/extra option like this
$extra->category->subcategory->prop = true; // we can set recursive properties, there's not any limit to own deep the hierarchy can be
+
$extra['category']['subcategory']['prop'] = true; // we can set recursive properties, there's not any limit to how deep the hierarchy can be
    
require_once(DOL_DOCUMENT_ROOT.'/customfields/class/customfields.class.php');
 
require_once(DOL_DOCUMENT_ROOT.'/customfields/class/customfields.class.php');
Line 131: Line 134:  
</source>
 
</source>
   −
You can also use addCustomField() or updateCustomField() with an $extra object, and these functions will also call the setExtra() method.
+
You can also use addCustomField() or updateCustomField() with an $extra array, and these functions will also call the setExtra() method.
   −
'''Note''': the extra options you set are '''appended''' to the one already stored in the database. However, you can overwrite them, just use the same name of property but with a different value.
+
'''Note''': the extra options you set are '''appended''' to the ones already stored in the database. However, you can also overwrite previous options, just use the same name of property but with a different value (the replacement is recursive, you can do it at any level in the hierarchy).
    
=== Fetching extra options ===
 
=== Fetching extra options ===
Line 161: Line 164:  
$fields = fetchAllFieldsStruct();
 
$fields = fetchAllFieldsStruct();
   −
$fields->mycustomfield->extra->newproperty = 'This is a new property'; // add a new property over the old extra options sub-object
+
$fields->mycustomfield->extra['newproperty'] = 'This is a new property'; // add a new property over the old extra options sub-object
 +
$fields->mycustomfield->extra['mycategory'] = 'Overwrite the old category'; // this will replace the previous value of 'mycategory' extra option
    
$customfields->setExtra('mycustomfield', $fields->mycustomfield->extra); // store the modified extra options back into the database for future usage
 
$customfields->setExtra('mycustomfield', $fields->mycustomfield->extra); // store the modified extra options back into the database for future usage
Line 215: Line 219:  
* fetchAllTables() fetch a list of all the tables in the database
 
* fetchAllTables() fetch a list of all the tables in the database
 
* fetchPrimaryField($table) fetch the column_name (and only the column_name!) of the primary field of a table. You can then use fetchFieldStruct()  with the column_name to get any information you want.
 
* fetchPrimaryField($table) fetch the column_name (and only the column_name!) of the primary field of a table. You can then use fetchFieldStruct()  with the column_name to get any information you want.
* fetchAny($columns, $table, $where='', $orderby='', $limitby='') allows you to issue any simple SQL query command, for example fetchAny('*', 'sometable') is equivalent to SELECT * FROM sometable; (but then everything is managed automatically and result is returned to you)
+
* fetchAny($columns, $table, $where='', $orderby='', $limitby='') allows you to issue any simple SQL query command, for example fetchAny('*', 'sometable') is equivalent to SELECT * FROM sometable; (but then everything is managed automatically and result is returned to you). NOTE: this method does NOT cache the database results, so that you always get the latest database state (whereas executeSQL() does cache queries to get faster responses).
 
* executeSQL($sql, $eventname) to execute any SQL query you want, this will return you a resource (and NOT a processed nuplet like fetchAny!). $eventname can be anything, it's just for Dolibarr logging facility.
 
* executeSQL($sql, $eventname) to execute any SQL query you want, this will return you a resource (and NOT a processed nuplet like fetchAny!). $eventname can be anything, it's just for Dolibarr logging facility.
 
* executeMultiSQL($sql, $eventname) to execute multiple SQL queries
 
* executeMultiSQL($sql, $eventname) to execute multiple SQL queries
Line 345: Line 349:     
Note: this method will always return an array of records object, for more consistency (and this is the main difference with fetch(null) ).
 
Note: this method will always return an array of records object, for more consistency (and this is the main difference with fetch(null) ).
 +
 +
=== Fetching referenced records of a constrained field ===
 +
 +
A constrained custom field points to another database table, and a value for this constrained field is the rowid of a record in the referenced table.
 +
 +
Thus, the principal purpose of a constrained custom field is not the value of the field in itself (it's simply an integer), but rather the other fields available from the referenced table, the constrained field being in fact just a pointer.
 +
 +
To fetch the remote record from the referenced table, use the fetchReferencedValuesList() of the CustomFields class:
 +
 +
<source lang="php">
 +
$fkrecord = fetchReferencedValuesList($field, $id=null, $where=null, $allcolumns=false);
 +
</source>
 +
 +
Where:
 +
 +
* $field is a custom field object (fetched using fetchFieldStruct() or fetchAllFieldsStruct()),
 +
* $id is the rowid of the record to get, just like fetch() and fetchAll(). Can be null to fetch all remote records (or to use the $where clause).
 +
* $where is a string without the WHERE clause (eg: "fk_facture=1") to get finer control. In this case, you can use $id or set $id=null depending on your purpose. This is mainly a private argument to allow for cascade option.
 +
* $allcolumns if false, it will fetch only the required columns to do the smart value substitution. If true, it will fetch all remote columns (useful for ODT substitution). If an array of strings, each string will be a column to fetch from the remote database.
 +
 +
Note that this function is NOT recursive (it will fetch the records from the referenced table, and that's all, it won't fetch the custom fields of the referenced table nor recursively fetch the remote constrained custom fields). To do recursive fetching, see in the Facade API.
 +
 +
Note2: this function automatically manages Smart Value Substitution depending of the $field->column_name.
 +
 +
=== Recursive fetching referenced records of a constrained field ===
 +
 +
If you want to recursively fetch a constrained field (eg: constrainedfield1->ref_table->constrainedfield2->ref_table2->...), you need another function called fetchReferencedValuesRec(). Technically, this function is in the Facade API (inside /customfields/lib/customfields_aux.lib.php), but it isn't meant to be used by lambda users (contrary to customfields_fill_object()), but is mainly a helper function for the rest of the facade API.
 +
 +
fetchReferencedValuesRec() works very similarly to fetchReferencedValuesList(), but it will work recursively.
 +
 +
<source lang="php">
 +
$fkrecord = fetchReferencedValuesRec($customfields, $field, $id, $recursive=true)
 +
</source>
 +
 +
Where $customfields is the CustomFields instance for the module you are working on, $field is the constrained field you want to fetch, $id is the record's id you want to fetch, and $recursive enables or disables the recursion.
 +
 +
Note that this function automatically manages Smart Value Substitution (and also recursively).
 +
 +
Note2: This function tries to automatically avoid an infinite recursion loop by using a $blacklist: for a given constrained custom field, a table won't be visited twice. This means that for example you can do: invoice->user->socpeople->invoice, this will work and every referenced fields will be fetched, but it will automatically stop the recursion at the second invoice, because else it could continue in a loop to user, socpeople, invoice, user, socpeople, etc.
 +
 +
Note3: when adding recursively referenced fields, the key in the returned array will be prefixed by the name of the custom field that led to those remote fields. Thus, you can have something like "cf_myfield1_cf_remotefield1_cf_remotefield2" if you have a constrained field cf_myfield1->cf_remotefield1->cf_remotefield2.
    
== Input forms for custom fields ==
 
== Input forms for custom fields ==
Line 361: Line 406:     
<source lang="php">
 
<source lang="php">
print $customfields->showInputField($field, $currentvalue=null, $moreparam='');
+
print $customfields->showInputField($field, $currentvalue=null, $moreparam='', $ajax_php_callback='');
 
</source>
 
</source>
   −
showInputField() takes 3 parameters:
+
showInputField() takes 4 parameters:
    
* $field is a CustomFields structure object (eg: returned by fetchFieldStruct()) and is necessary to detect the right datatype and the possible values.
 
* $field is a CustomFields structure object (eg: returned by fetchFieldStruct()) and is necessary to detect the right datatype and the possible values.
 
* $currentvalue is the current value if you want to preselect a value (for example if the user already defined a value, you can reload it here). This is optional, in case it is not defined, either a null/empty value will be chosen, or either the default value defined when creating the custom field.
 
* $currentvalue is the current value if you want to preselect a value (for example if the user already defined a value, you can reload it here). This is optional, in case it is not defined, either a null/empty value will be chosen, or either the default value defined when creating the custom field.
 
* $moreparam is used to add more HTML attributes, if you want for example to add some css styling or whatever you want.
 
* $moreparam is used to add more HTML attributes, if you want for example to add some css styling or whatever you want.
 +
* $ajax_php_callback is optional and allows to specify the relative url to the php callback script. If specified, an AJAX script will be automatically attached to this field (see AJAX-PHP callback below).
    
showInputField() only prints ONE HTML input field, thus you have to enclose it/them by your own HTML form.
 
showInputField() only prints ONE HTML input field, thus you have to enclose it/them by your own HTML form.
Line 400: Line 446:  
print $customfields->showInputForm($id, $field, $currentvalue=null, $idvar='id', $page=null, $moreparam='');
 
print $customfields->showInputForm($id, $field, $currentvalue=null, $idvar='id', $page=null, $moreparam='');
 
</source>
 
</source>
 +
 +
=== AJAX-PHP callback ===
 +
 +
'''showInputFieldAjax()''' will output an AJAX script (using jQuery) to send and receive data to and from a specified php script. The AJAX script will automatically manage HTML form input's updating as long as the received data follows some convention.
 +
 +
An AJAX script can be attached to any field (including non-CustomFields) by using the method:
 +
 +
<source lang="php">
 +
print $customfields->showInputFieldAjax($id, $php_callback_url, $on_func="change", $request_type="post");
 +
</source>
 +
 +
Where:
 +
* $id is the HTML id of the field you want to attach the AJAX to.
 +
* $phpcallback the relative path from Dolibarr's htdocs root folder to the php script that will receive and send back data.
 +
* $on_func is the Javascript or jQuery event that should trigger the AJAX script (by default on change).
 +
* $request_type is the HTML query type that will be used to send the data to the PHP callback (either "get" or "post").
 +
 +
The AJAX script will automatically manage sending/receiving of data:
 +
 +
* automatically send all form's inputs values, as well as the current calling field's name and value. The sending happens on change by default, but another event can be set using the $on_event argument. Data will be sent using standard GET or POST.
 +
* Upon reception of data from the php script, the AJAX script will automatically parse the data and update the HTML fields.
 +
 +
The PHP callback script must send back to AJAX the data in JSON encoded format, and with with a specific format:
 +
 +
* the data must be an associative array, where each entry's key is the name (not ID!) of an HTML field to update.
 +
* each entry's value is an associative array, where each sub-entry's key is the action to do. Available actions: 'options', 'value', 'html', 'alert'.
 +
* each sub-entry's value is the value for this action and HTML field.
 +
 +
Thus, this approach allows to generically support a wide range of updating actions, managed automatically.
 +
 +
You, the implementer, have just to edit the PHP callback script and return an associative array defining what action you want for each field you want to update. This is exactly what has been implemented in the Custom AJAX Functions library, which simplifies even more your job by managing automatically the step described here (generating AJAX and formatting data), so that you can focus on '''making the data'''.
    
== Printing custom fields in documents ==
 
== Printing custom fields in documents ==
Line 426: Line 503:     
Another method '''printFieldPDF()''' can be used to properly print a value for a PDF (properly encoding the characters).
 
Another method '''printFieldPDF()''' can be used to properly print a value for a PDF (properly encoding the characters).
 +
 +
Powertip: this function can also be used to get the Smart Value Substituted value of the field (instead of printing the rowid) in the field is constrained.
    
=== Simple printing in documents ===
 
=== Simple printing in documents ===
Line 443: Line 522:     
Another method '''simpleprintFieldPDF()''' can be used to properly print a value for a PDF (properly encoding the characters).
 
Another method '''simpleprintFieldPDF()''' can be used to properly print a value for a PDF (properly encoding the characters).
 +
 +
Powertip: this function can also be used to get the Smart Value Substituted value of the field (instead of printing the rowid) in the field is constrained.
    
=== Find the label ===
 
=== Find the label ===
Line 525: Line 606:  
* /customfields/core/substitutions/functions_customfields.lib.php --- CustomFields substitution class for ODT generation : necessary to support customfields tags in ODT files
 
* /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. You should not modify this file but you should add your triggers in $triggersarray inside conf_customfields.lib.php, but if you really have a special need and know what you do, you can edit this file to directly add your own triggers. 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/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. You should not modify this file but you should add your triggers in $triggersarray inside conf_customfields.lib.php, but if you really have a special need and know what you do, you can edit this file to directly add your own triggers. 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: this is where implementers can use their own php code to manage the custom fields they want (one function per action and per field).
+
* /customfields/fields/customfields_fields_extend.lib.php.example --- Overloading functions library with users functions: this is where implementers can use their own php code to manage the custom fields they want (one function per action and per field).
 +
* /customfields/fields/customfields_fields_ajax_custom.lib.php.example --- Custom AJAX functions library with users functions: this is where implementers can use their own php code to manage the custom fields cascading and AJAX calls, similarly to the Overloading functions library (one function per action and per field).
 
* /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.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/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). This is what you should use for most of your needs.
 
* /customfields/lib/customfields_aux.lib.php --- Simplifier library to easily use CustomFields class to populate an $object with custom fields datas (Facade design pattern). This is what you should use for most of your needs.
 
* /customfields/lib/customfields_printforms.lib.php --- Core printing library for records : contains only printing functions, there's not really any core functions inside but it allows to manage the printing of the custom fields records and their editing.
 
* /customfields/lib/customfields_printforms.lib.php --- Core printing library for records : contains only printing functions, there's not really any core functions inside but it allows to manage the printing of the custom fields records and their editing.
 +
* /customfields/lib/customfields_ajax_wrapper.lib.php --- AJAX wrapper library to automatically manage cascading at objects creation. This isn't really necessary for CustomFields to function, this is more an addition to allow dynamical AJAX updating, but CustomFields core functionalities can work without this library.
 
* /customfields/sql/*.sql --- Unused (the tables are created directly via a function in the customfields.class.php) - but the sql files are still valid, they were used as squeletton in the first designs.
 
* /customfields/sql/*.sql --- Unused (the tables are created directly via a function in the customfields.class.php) - but the sql files are still valid, they were used as squeletton in the first designs.
   Line 811: Line 894:     
<source lang="php">
 
<source lang="php">
$parameters=array('line'=>$line,'fk_parent_line'=>$line->fk_parent_line);
+
$parameters=array('line'=>$line);
   −
echo $hookmanager->executeHooks('formEditProductOptions',$parameters,$this,$action);
+
echo $hookmanager->executeHooks('formEditProductOptions',$parameters,$object,$action);
 
</source>
 
</source>
   −
Hooks names:
+
The two important things here are that you supply:
* formEditProductOptions
+
* $line: the line object, with a $line->rowid property.
* formCreateProductOptions ($line is not required here, because we create a new product line! you can leave $parameters=array(); empty).
+
* $object: the parent object of the line, with a $object->rowid property. For example, if $line is an invoice line, then $object must be the parent invoice object. This is necessary so that CustomFields can automatically recognize the link between the twos.
 +
 
 +
Possible hooks names:
 +
* formEditProductOptions: called when you edit a line.
 +
* formCreateProductOptions: called when you create a line. $line is not required here, because we create a new product line! you can leave $parameters=array(); empty.
 
Note: there's no hook for viewing, because showing the customfields will clutter the visual field, but if you really want you can also do it by adding a formViewProductOptions hook.
 
Note: there's no hook for viewing, because showing the customfields will clutter the visual field, but if you really want you can also do it by adding a formViewProductOptions hook.
   Line 941: Line 1,028:     
== To Do ==
 
== To Do ==
Nothing here!
+
 
 +
* Better management of hidden fields with custom cascading (eg: works great on creation form, but on edit form and creation form with edit action, if the parents already have a value, the hidden fields will stay hidden! This is because of the AJAX is not called, and this is normal). -> Propose a better custom cascade function storing the hidden field's state inside extraoptions?
 +
 
 +
== To Document ==
 +
* Automatic recopy on cloning for custom fields and products' lines custom fields.
 +
* new API function: customfields_clone_or_recopy($object, $fromobject, $action2 = null)
    
== Should do ==
 
== Should do ==
 +
* Add the possibility to mark a custom field to be shown in tables listings (eg: as a column in products listings) with "order by this column" buttons and stuffs. Will be difficult if the hooks are not yet implemented in listings.
 
* 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)
 
* 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:
 
use fieldset, input checkbox and label for, eg:
Line 951: Line 1,044:  
     etc...
 
     etc...
 
     </fieldset>
 
     </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).
 
* 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).
* Replace triggers in customfields class by hookmanager.
+
* Replace triggers in customfields class by hookmanager?
* Replace extend class by hookmanager if possible (but how to simulate the *full switch?).
  −
* Add the possibility to make a custom field uneditable (only filled using overloading functions).
  −
* Add the possibility to make a custom field required to create an object (use JSON extraoptions).
  −
* Add the possibility to mark a custom field to be shown in tables listings (eg: as a column in products listings) with "order by this column" buttons and stuffs. Will be difficult if the hooks are not yet implemented in listings.
  −
* Automatically on conversion trigger, copy the custom fields that have the same name (eg: cf_theme exists in both propal and invoice, then when converting propal -> invoice the custom field will be copied automatically).
   
* AJAX previsualisation of the HTML custom field that will be created.
 
* AJAX previsualisation of the HTML custom field that will be created.
 
* In ODTs, create special tags to directly access day, month or year value of a date type field independently of the rest.
 
* In ODTs, create special tags to directly access day, month or year value of a date type field independently of the rest.
* Automatically copy custom fields if extra option "migrate" is enabled and a target custom field with the same name exists? Needs to catch the right event (validate?) - maybe with a trigger?
   
* New overloading function's action: "get", similar to view except that it works not only on Dolibarr's view but whenever someone tries to access this field's value.
 
* New overloading function's action: "get", similar to view except that it works not only on Dolibarr's view but whenever someone tries to access this field's value.
* Implementation of custom fields in CSV exports (may need a few new hooks in Dolibarr?).
   
* Add Upload and Image field types (this would allow for an easier integration inside ODT and PDF templates than the current workflow of Dolibarr).
 
* Add Upload and Image field types (this would allow for an easier integration inside ODT and PDF templates than the current workflow of Dolibarr).
   Line 969: Line 1,054:  
* 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).
 
* 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).
 
* ficheinter (Intervention module) custom fields will stay in create mode just after create page is submitted (this is because of the $action that is not standard - $action=edit or something).
 
* ficheinter (Intervention module) custom fields will stay in create mode just after create page is submitted (this is because of the $action that is not standard - $action=edit or something).
* after the edition or creation of a custom field for product lines, the fields in the creation zone are still prefilled with the last entered values of the custom fields (they should be empty, but the problem is that CustomFields automatically reload the last values entered in case there is an error, and the problem lies in the fact that after the creation/edition of a product line, there is absolutely no way to know if the page was reloaded due to an error or if everything is OK). Usually with other modules and mechanisms of Dolibarr, after creation/edition, the page is reloaded and $action is changed, but here it doesn't.
  −
Maybe solution: look at the $object->$error or $object->$errors? but this is not a safe way, the variable name may change, or the error may be emptied, or may not even be set altogether depending on the error...
      
== Never/Maybe one day ==
 
== Never/Maybe one day ==
 
* 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).
 
* 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)
+
* Add an AJAX select box for constrained values to automatically select the appropriate name for Smart Value Substitution : 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).
* Add an AJAX select box for constrained 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).
  −
* Enhance date picker for date and datetime types by using jquery datepicker.
  −
* Find a way to make constrained subfields (constrained on another custom field on the same object) to work in creation page (it only works in edition page for now because the previous field must be set and registered in db before the next field can fetch its value from the database). Maybe something with AJAX? (but can't autosave using AJAX because at creation we don't yet know the object ID, so we would need to use something like a simple Javascript get value then use AJAX to fetch the values for the subfield...).
   
* Fine-grained rights management: rights per group, per user, and per field.
 
* Fine-grained rights management: rights per group, per user, and per field.
 +
* Replace overloading functions (extend class) by hookmanager if possible (but how to simulate the *full switch? Plus this will force users to make their own modules to make those functions, and to disable/renable their modules everytime they will add a new function...).
 +
* 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'). But the triggers aren't necessarily associated with a specific module...
 +
* AJAX autocompletion / auto population of field's content when typing the beginning of a value in a text box.