Upcoming Events
San Francisco CiviCRM Meetup - March 2010
March 24th, 2010
Come meet others from the Bay Area who are interested in, using or developing (more...)
Campaigning Camp in Oxford, UK
March 25th, 2010
Free (with lunch and tea break included!) CiviCRM/Drupal and Plone two-track (more...)
CiviCRM Seminar - Dublin
March 25th, 2010
MTL Software Solutions are hosting a free seminar at The IBOA, Stephen
St (more...)
CiviCRM User Training - Atlanta (pre NTC)
April 7th, 2010
This full-day hands-on training session is aimed at non-profit staff and (more...)
Configuring, Customizing and Extending CiviCRM - San Francisco (before DrupalCon SF)
April 18th, 2010
This hands-on 1-day training session is targeted at administrators, integrators (more...)
CiviCRM User Training - San Francisco (before DrupalCon SF) This full-day hands-on training session is aimed at non-profit staff and (more...)
April 18th, 2010
CiviCon San Francisco 2010
April 22nd, 2010
Join us for the first ever CiviCon in San Francisco this April! CiviCon brings (more...)
Setting and Getting Custom Field Values in CiviCRM Hooks
- Not Just a Contact Database
-
These optional components give you more power to connect and engage your supporters.

civiCONTRIBUTE
Online fundraising and donor management.

civiEVENT
Online event registration and participant tracking.

civiMEMBER
Online signup and membership management.

civiMAIL
Personalized email blasts and newsletters.

civiREPORT
Report generation and template management.
Cross-posted at The Nerdy Adventures of Wes.
CiviCRM isn't always the most predictable codebase. Recently I needed to get and set some custom field values in a hook I was writing. The hook's job was to calculate some custom field values and create some contact references when a contribution was created or updated. As always, dlobo was a huge help (he's the CiviCRM guru, find him in #civicrm on Freenode). Here's what I did to set a couple of custom fields in my _pre hook:
$custom_fields = array('foo' => 'custom_1', 'bar' => 'custom_2');
function modulename_civicrm_pre ($op, objectName, $objectId, &$objectRef) {
if ($objectName != 'Contribution' || ($op != 'edit' && $op != 'create')) {
return;
}
$contribution_id = $objectId;
require_once 'CRM/Core/BAO/CustomValueTable.php';
$my_foo = 'blah';
$my_bar = 'baz';
$set_params = array('entityID' => $contribution_id,
$custom_fields['foo'] => $my_foo, $custom_fields['bar'] => $my_bar);
CRM_Core_BAO_CustomValueTable::setValues($set_params);
}
And here's an example for retrieving some custom field values from the contact object in the same hook:
$custom_fields = array('contact_foo' => 'custom_3', 'contact_bar' => 'custom_4');
function modulename_civicrm_pre ($op, objectName, $objectId, &$objectRef) {
if ($objectName != 'Contribution' || ($op != 'edit' && $op != 'create')) {
return;
}
// set the field names to 1 that we want to get back
$get_params = array('entityID' => $objectRef['contact_id'],
$custom_fields['contact_foo'] => 1, $custom_fields['contact_bar'] => 1);
require_once 'CRM/Core/BAO/CustomValueTable.php';
$values = CRM_Core_BAO_CustomValueTable::getValues($get_params);
$my_cfoo = $values[$custom_fields['contact_foo']];
$my_cbar = $values[$custom_fields['contact_bar']];
}
So it's not ideal that you have to hard-code the custom field IDs; there should be a way to look them up (maybe there is). But it's not the worst thing in the world unless you're in the habit of destroying and recreating your custom fields from time to time. Probably you're not on a production system.







Comments
added function to get custom field ID
given the field label and an optional group title:
http://issues.civicrm.org/jira/browse/CRM-5805
this will be part of 3.1.2
looking up custom fields
I am in the habit of destroying and recreating my custom fields. :-) Therefore I wrote a function that looks up the custom table name and field names, so that I can use them in the 'real' SQL statements. The function relies on the label for the custom field group and the fields. So as long as the labels stay the same, the code works.
Here is my function, which could be improved on:
function getCustomTableFieldNames(){
//*** Start of section to get table and column names ***/
# Change the next 3 variables to match the labels of the custom field group.
$custom_field_group_label = "Extended Date Information";
$custom_field_birthdate_sunset_label = "Birth Date Before Sunset";
$custom_field_deathdate_sunset_label = "Death Date Before Sunset" ;
/* rest of the function */
$return_custom_birth_sunset = '';
$return_custom_death_sunset = '';
$error_msg = '';
// figure out the table names and field names for custom fields.
$tablename_query = "SELECT civicrm_custom_group.table_name as tablename from civicrm_custom_group
where title = '$custom_field_group_label' and extends = 'Individual' ";
$extended_date_table = '';
$table_dao =& CRM_Core_DAO::executeQuery( $tablename_query );
if ( $table_dao->fetch( ) ) {
$extended_date_table = $table_dao->tablename;
}else{
$error_msg = "Cannot find table for custom field group '$custom_field_group_label'";
$return_values = array( $error_msg, $return_custom_birth_sunset , $return_custom_death_sunset );
return $return_values;
}
$table_dao->free( );
if( $extended_date_table == ''){
$error_msg = "extended_date_table variable is empty";
$return_values = array( $error_msg, $return_custom_birth_sunset , $return_custom_death_sunset );
return $return_values;
}
$date_fields_query = " SELECT civicrm_custom_field.column_name as column_name, civicrm_custom_field.label as label
FROM civicrm_custom_group left join civicrm_custom_field
on civicrm_custom_group.id = civicrm_custom_field.custom_group_id
where civicrm_custom_group.title = '$custom_field_group_label'
and civicrm_custom_group.extends = 'Individual'
and ( civicrm_custom_field.label = '$custom_field_birthdate_sunset_label' or
civicrm_custom_field.label = '$custom_field_deathdate_sunset_label' ) ";
//print "";
$fieldnames_dao =& CRM_Core_DAO::executeQuery( $date_fields_query );
while ( $fieldnames_dao->fetch( ) ) {
$tmp_label = $fieldnames_dao->label;
if($tmp_label == $custom_field_birthdate_sunset_label){
$extended_birth_date = $fieldnames_dao->column_name;
}else if($tmp_label == $custom_field_deathdate_sunset_label ){
$extended_death_date = $fieldnames_dao->column_name;
}
}
if($extended_birth_date == "" || $extended_death_date == ""){
$error_msg = "Cannot find custom field names for before sunset flags for date of birth or date of death";
$return_values = array( $error_msg, $return_custom_birth_sunset , $return_custom_death_sunset );
return $return_values;
}
$fieldnames_dao->free( );
//*** end of section to get table and column names ***/
$return_values = array( $error_msg, $extended_date_table, $extended_birth_date , $extended_death_date );
return $return_values;
}
lookup shoud be in the core
what is the license? public domain and can be recopyrighted ? academic free ?
custom fields
The code I pasted in my previous comment is GPL. Actually I would prefer to see more control given when creating a custom field group. Perhaps the option to do this could be collapsed for "begining" users and expanded for "advanced" users.
The problem I see even with the lookup routine that I wrote: If a end-user changes the label, then my code for custom hooks, reports, etc will break. If I had control over the actual table name and field name in the database, then the end-user could change the labels without worry.
Also for multi-lingual setups, I cannot rely on the label being a known value.