CiviCRM Community Forums (archive)

*

News:

Have a question about CiviCRM?
Get it answered quickly at the new
CiviCRM Stack Exchange Q+A site

This forum was archived on 25 November 2017. Learn more.
How to get involved.
What to do if you think you've found a bug.



  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion »
  • APIs and Hooks (Moderator: Donald Lobo) »
  • Correct way to update field through hook_civicrm_post?
Pages: [1]

Author Topic: Correct way to update field through hook_civicrm_post?  (Read 673 times)

mallezie

  • I post occasionally
  • **
  • Posts: 33
  • Karma: 0
  • CiviCRM version: 4.5
  • CMS version: Drupal
  • PHP version: 5.4
Correct way to update field through hook_civicrm_post?
April 29, 2015, 06:44:59 am
I've stumbled on a strange problem / bug today.

We're using a hook_civicrm_post to update the sort and display name on our contacts. That's because they have a different format for organizations and individuals, and the hook gives the flexibility to play with that.

Previously i've used the following (simplified) code for that.
   
function HOOK_civicrm_post($op, $objectName, $objectId, &$objectRef) {   
  if ($objectName == 'Individual' && ($op == 'edit' || $op == 'create')) {   
    $objectRef->display_name = $objectRef->last_name;
    $objectRef->save();   
  }   
  if ($objectName == 'Organization' && ($op == 'edit' || $op == 'create')) {
    $objectRef->display_name = $objectRef->legal_name;
    $objectRef->save();   
  }   
}   

This sets the display_name for individuals to the last name, and for organizations to the legal name.
When updating a contact throught the UI this works correctly. The problem exists when we update one of those contacts throught the API.
For example we set them to 'do no mail'.
drush cvapi Contact.create sequential=1 id=1 do_not_email=1
This causes the display name to be set to '' (empty string).

The reason herefore lies in the passed $objectRef variable.
When you do this through the ui

$objectRef passed through ui (simplified)

id (String, 5 characters ) 11854
contact_type (String, 12 characters ) Organization
contact_sub_type (String, 7 characters ) Ploeg
do_not_email (String, 0 characters )
do_not_phone (String, 0 characters ) Get path
do_not_mail (String, 0 characters )
do_not_sms (String, 0 characters )
do_not_trade (String, 0 characters )
is_opt_out (Boolean) FALSE
legal_identifier (NULL)
external_identifier (String, 3 characters ) 5IF
sort_name (String, 20 characters ) Wgr. informatisering
display_name (String, 20 characters ) Wgr. informatisering
nick_name (String, 4 characters ) null
legal_name (String, 20 characters ) Wgr. informatisering
image_URL (NULL)
preferred_communication_method (String, 0 characters )
...

When updated through the API only the API-defined fields are filled in.

id (Integer) 11854
contact_type (String, 12 characters ) Organization
contact_sub_type (NULL)
do_not_email (Integer) 1
do_not_phone (NULL)
do_not_mail (NULL)
do_not_sms (NULL)
do_not_trade (NULL)
is_opt_out (NULL)
legal_identifier (NULL)
external_identifier (NULL) Get path
sort_name (NULL)
display_name (NULL)
nick_name (NULL)
legal_name (NULL)
image_URL (NULL)
preferred_communication_method (NULL)
...

This is sort of logical since we didn't pass the values in the API-call. While in the form, those have a value.

To solve this problem is have to check explicitly if there is already a defined value, which is different before updating.


function HOOK_civicrm_post($op, $objectName, $objectId, &$objectRef) {
    if (empty($objectRef->last_name)) {
      $objectRef->last_name = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $objectId, 'last_name');
    }
    $objectRef->display_name = $objectRef->last_name;
    $objectRef->sort_name = $objectRef->display_name;
    $objectRef->save();
  }
  if ($objectName == 'Organization' && ($op == 'edit' || $op == 'create')) {
    if (empty($objectRef->legal_name)) {
      $objectRef->legal_name = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $objectId, 'legal_name');
    }
    $objectRef->display_name = $objectRef->legal_name;
    $objectRef->save();
  }
}


This makes this method much more complex. (Especially since my real generated sort name depends on much more fields, and for example when using address fields of the contact the explicit call get's even more complex.
I was wondering if there was a better way? Or is this a bug, and should we fix this somehow?

Erik Hommel

  • Forum Godess / God
  • I live on this forum
  • *****
  • Posts: 1773
  • Karma: 59
    • EE-atWork
  • CiviCRM version: all sorts
  • CMS version: Drupal
  • MySQL version: Ubuntu's latest LTS version
  • PHP version: Ubuntu's latest LTS version
Re: Correct way to update field through hook_civicrm_post?
April 29, 2015, 11:51:54 pm
With the API the assumption is that the developer is in control, so if he passes empty values there will be empty values set. This is per design, although it can be cumbersome as you have noted :-). What I tend to do is retrieve the existing contact with an API getsingle action, set all the objectRef values with the retrieved once in one action and update the required ones?
Consultant/project manager at EEatWork and CiviCooP (http://www.civicoop.org/)

mallezie

  • I post occasionally
  • **
  • Posts: 33
  • Karma: 0
  • CiviCRM version: 4.5
  • CMS version: Drupal
  • PHP version: 5.4
Re: Correct way to update field through hook_civicrm_post?
April 29, 2015, 11:56:16 pm
Thanks Erik!
I sort of see the logic in your explanation. However i'm not really passing empty values, but no values at all. And the api-call gets executed to only update the passed values, and leave the non-passed fields at ther value.
I'm not sure if we could perhaps 'fix' this by filling the $objectRef value with the current values, and then add the API-defined values to it, before passing to the hooks?
Just thinking out loud heree.

Erik Hommel

  • Forum Godess / God
  • I live on this forum
  • *****
  • Posts: 1773
  • Karma: 59
    • EE-atWork
  • CiviCRM version: all sorts
  • CMS version: Drupal
  • MySQL version: Ubuntu's latest LTS version
  • PHP version: Ubuntu's latest LTS version
Re: Correct way to update field through hook_civicrm_post?
April 30, 2015, 01:37:35 am
Hi Tim,

alternative is to change the API for your instance, but that would not be really nice :-). The API behaviour can be discussed, but is per design and consistent with other API's as far as I know. You are welcome to start a discussion for your proposed solution, and I would be in favor. But I do not think we need consistent behaviour in the API' s so that might mean a somewhat larger project? That is the main reason why I tend to accept what the API does as long as it is consistent and model my working practises around it :-)
Consultant/project manager at EEatWork and CiviCooP (http://www.civicoop.org/)

mallezie

  • I post occasionally
  • **
  • Posts: 33
  • Karma: 0
  • CiviCRM version: 4.5
  • CMS version: Drupal
  • PHP version: 5.4
Re: Correct way to update field through hook_civicrm_post?
April 30, 2015, 01:47:01 am
Thanks for the update.

For now i see this is expected behaviour. Patching my own instance would be indeed overkill for this situation, then my current solution, or your suggestion is much better.
My first question was to see if i did something wrong, seems i'm not, so thanks for the answers!

If i can find time to make a POC, it could be a start to discuss this further.

xavier

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4453
  • Karma: 161
    • Tech To The People
  • CiviCRM version: yes probably
  • CMS version: drupal
Re: Correct way to update field through hook_civicrm_post?
April 30, 2015, 03:40:23 am
Hold on, sounds weird, is this for an org or an individual? are the first+lastname set?

display name is a weird field, as it's autogenerated based on other fields. Are they set in your case?
-Hackathon and data journalism about the European parliament 24-26 jan. Watch out the result

mallezie

  • I post occasionally
  • **
  • Posts: 33
  • Karma: 0
  • CiviCRM version: 4.5
  • CMS version: Drupal
  • PHP version: 5.4
Re: Correct way to update field through hook_civicrm_post?
April 30, 2015, 03:55:47 am
hi xavier,

It doesn't really make a difference for on organization or an individual. But the values used here, first_name, last_name, legal_name are indeed set. The difference lies in the values of the $objectRef object.
When using the UI the objectRef get's all values (set by the form values). So display_name / last_name / first_name no matter they're changed or not. Since the form has their values, and put's them into $objectRef. However when you use the api only the specified values are set in the $objectRef

The code for changing the display name does that way exactly what it's says actually. When updating through the UI it contains the value for the last_name (and the changed one if you changed it), so the display name becomes that value. When updating throught the API (and not specifying the first_name) that field is NULL in the $objectRef so the display name becomes NULL as well.

My problem was acutally that i was expecting the $objectRef to contain all values of the object changed, not only the changed values.

Pages: [1]
  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion »
  • APIs and Hooks (Moderator: Donald Lobo) »
  • Correct way to update field through hook_civicrm_post?

This forum was archived on 2017-11-26.