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) »
  • Context required in civicrm_pre and civicrm_post hook
Pages: [1]

Author Topic: Context required in civicrm_pre and civicrm_post hook  (Read 1662 times)

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
Context required in civicrm_pre and civicrm_post hook
May 15, 2013, 02:28:30 am
Issue: when I am in the civicrm_pre or civicrm_post hook I would like to know if an object action originates from the API or from another spot. I need this in case I am using the API for data synchronization. If for example a phone was created I want to know if this creates comes from CiviCRM (and therefore needs to be synchronized) or from the API (and therefore can be ignored as it originates from the other system in the first place).

I just discussed this with Eileen on IRC and we believe the best solution would be to add a context variable to the civicrm_pre and to the civicrm_post hook. The context variable would get a default value of "civicrm". Action would be to change all the calls to the civicrm_pre and civicrm_post hook to have this variable and pass it to the hook.
In the API calling the create function the context would be set to "api". In the actual hook the developer of an extension can then elect to use this variable to do or not do something. I would use it to ignore the synchronization process if the origin is the api.

Does this make sense? Any thoughts on the subject?
Consultant/project manager at EEatWork and CiviCooP (http://www.civicoop.org/)

xavier

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4453
  • Karma: 161
    • Tech To The People
  • CiviCRM version: yes probably
  • CMS version: drupal
Re: Context required in civicrm_pre and civicrm_post hook
May 15, 2013, 06:19:24 am
Hi,

having a context is something that would have been handy quite a few times. instead of api and civicrm, I'd rather have api and CRM as naming convention (ie. the top folder), as api belongs to civicrm too.

Should we go a step further and say it's api php, api rest or api ajax? same goes for the UI, specify which form?

Because as some UI is already using the api, you would have a api context action that would need sync.

X+
-Hackathon and data journalism about the European parliament 24-26 jan. Watch out the result

JoeMurray

  • Administrator
  • Ask me questions
  • *****
  • Posts: 578
  • Karma: 24
    • JMA Consulting
  • CiviCRM version: 4.4 and 4.5 (as of Nov 2014)
  • CMS version: Drupal, WordPress, Joomla
  • MySQL version: MySQL 5.5, 5.6, MariaDB 10.0 (as of Nov 2014)
Re: Context required in civicrm_pre and civicrm_post hook
May 15, 2013, 06:24:00 am
I'm in favour of adding a context for these purposes, but don't have strong opinions on the details of the implementation at this point.

I think there may be other uses for this notion of context in the future besides just api or civicrm. In Drupal they have found context to be quite useful as an abstract concept. In other hooks we are using context by other names, eg the form_name or the operation is passed in and generally checked.

At this point it might be useful to allow the context to be passed _in_ from API calls though defaulted to 'api' if not passed. Just a thought.
Co-author of Using CiviCRM https://www.packtpub.com/using-civicrm/book

JoeMurray

  • Administrator
  • Ask me questions
  • *****
  • Posts: 578
  • Karma: 24
    • JMA Consulting
  • CiviCRM version: 4.4 and 4.5 (as of Nov 2014)
  • CMS version: Drupal, WordPress, Joomla
  • MySQL version: MySQL 5.5, 5.6, MariaDB 10.0 (as of Nov 2014)
Re: Context required in civicrm_pre and civicrm_post hook
May 15, 2013, 06:25:46 am
X+ posted while I was composing. I like his ideas of distinguishing the different forms of api calls, and would want in addition to see the possibility of overriding the value.
Co-author of Using CiviCRM https://www.packtpub.com/using-civicrm/book

totten

  • Administrator
  • Ask me questions
  • *****
  • Posts: 695
  • Karma: 64
Re: Context required in civicrm_pre and civicrm_post hook
May 15, 2013, 10:18:57 am
Quote from: Erik Hommel on May 15, 2013, 02:28:30 am
Issue: when I am in the civicrm_pre or civicrm_post hook I would like to know if an object action originates from the API or from another spot. I need this in case I am using the API for data synchronization. If for example a phone was created I want to know if this creates comes from CiviCRM (and therefore needs to be synchronized) or from the API (and therefore can be ignored as it originates from the other system in the first place).

I'm not sure this inference is valid -- it rests on the assumption that *only* the "other system" makes API calls (i.e. that the core application does *not* make API calls, and that there are no other third-party integrations making API calls). These assumptions may be valid on particular installations (esp. old, vanilla CiviCRM versions), but satisfying those assumptions will be harder in newer/future installations (b/c core code increasingly does call the API -- and b/c third-party modules/extensions are becoming more common).

Joe Murray's suggestion of passing the context designation *into* the API could resolve this -- e.g.

Code: [Select]
// Make API call
civicrm_api('contact', 'create', array(
  'id' => 3,
  'first_name' => 'Bob',
  'api.context' => array(
    'disable_datasync1 => TRUE,
  )
));

...

// Define the hook
function datasync1_civicrm_post($op, $objectName, $objectId, &$objectRef, $context = NULL) {
  if (isset($context['disable_datasync1'])) {
    return;
  }
  // we're not in a sync context, so send the changes to external service #1
}

Notably, this still works in cases where there are 2 (or 3 or more) modules which all use the same data-sync pattern.

Code: [Select]
function datasync2_civicrm_post($op, $objectName, $objectId, &$objectRef, $context = NULL) {
  if (isset($context['disable_datasync2'])) {
    return;
  }
  // we're not in a sync context, so send the changes to external service #2
}
function datasync3_civicrm_post($op, $objectName, $objectId, &$objectRef, $context = NULL) {
  if (isset($context['disable_datasync3'])) {
    return;
  }
  // we're not in a sync context, so send the changes to external service #3
}

When service #1 pushes data into Civi, the Civi hooks won't circularly push the data back to service #1; but Civi will push data onto services #2 and #3.

Personally, though, if I were trying to do this (esp. on an older installation), it would seem like a lot of work/risk to get the $context passed through all the possible hook invocations. I'd plug my nose and use a global variable:

Code: [Select]
// Make API call
global $datasync1_options;
$datasync1_options['disable'] = TRUE;
civicrm_api('contact', 'create', array(
  'id' => 3,
  'first_name' => 'Bob',
));
unset($datasync1_options['disable']);

...

// Define the hook
function datasync1_civicrm_post($op, $objectName, $objectId, &$objectRef) {
  global $datasync1_options;
  if (isset($datasync1_options['disable'])) {
    return;
  }
  // we're not in a sync context, so send the changes to external service #1
}

Coleman Watts

  • Administrator
  • I’m (like) Lobo ;)
  • *****
  • Posts: 2346
  • Karma: 183
  • CiviCRM version: The Bleeding Edge
  • CMS version: Various
Re: Context required in civicrm_pre and civicrm_post hook
May 15, 2013, 03:56:36 pm
Erik I'm sure you've thought of this but if you want a cheap (but not in terms of CPU) quick fix you can use debug_backtrace()
Try asking your question on the new CiviCRM help site.

xavier

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4453
  • Karma: 161
    • Tech To The People
  • CiviCRM version: yes probably
  • CMS version: drupal
Re: Context required in civicrm_pre and civicrm_post hook
May 15, 2013, 09:48:55 pm
Along the Tim nose plugin solution this should catch every case of human+browser being the context:

Code: [Select]
function hook_civicrm_postProcess ( $formName, &$form )) {
$GLOBALS["datasync_from_UIForm"]=$formName;
}

function hook_civicrm_post (...) {
if (array_key_exists("datasync_from_UIForm",$GLOBALS)) {
//needs to be synced because it comes from a form.
}

if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
//needs to be synced because it comes from an ajax call.
}

}

-Hackathon and data journalism about the European parliament 24-26 jan. Watch out the result

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: Context required in civicrm_pre and civicrm_post hook
May 16, 2013, 12:38:02 am
Coleman,
I had not, thanks.....
Quote
Erik I'm sure you've thought of this but if you want a cheap (but not in terms of CPU) quick fix you can use debug_backtrace()
Consultant/project manager at EEatWork and CiviCooP (http://www.civicoop.org/)

JoeMurray

  • Administrator
  • Ask me questions
  • *****
  • Posts: 578
  • Karma: 24
    • JMA Consulting
  • CiviCRM version: 4.4 and 4.5 (as of Nov 2014)
  • CMS version: Drupal, WordPress, Joomla
  • MySQL version: MySQL 5.5, 5.6, MariaDB 10.0 (as of Nov 2014)
Re: Context required in civicrm_pre and civicrm_post hook
May 16, 2013, 10:12:57 am
Erik, could you summarize what you will be taking away from this discussion? Or should we just wait for API v4? ;)
Co-author of Using CiviCRM https://www.packtpub.com/using-civicrm/book

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: Context required in civicrm_pre and civicrm_post hook
May 17, 2013, 12:28:36 am
Joe,
first of all I am going to try the context solution for my own project, which involves only a couple of entities. Based on that I will put a description together, raise an issue and estimate how much time will be involved. I am guessing it is not a quick bug....and then probably aim to tackle it during a sprint?
Consultant/project manager at EEatWork and CiviCooP (http://www.civicoop.org/)

JoeMurray

  • Administrator
  • Ask me questions
  • *****
  • Posts: 578
  • Karma: 24
    • JMA Consulting
  • CiviCRM version: 4.4 and 4.5 (as of Nov 2014)
  • CMS version: Drupal, WordPress, Joomla
  • MySQL version: MySQL 5.5, 5.6, MariaDB 10.0 (as of Nov 2014)
Re: Context required in civicrm_pre and civicrm_post hook
May 17, 2013, 05:42:58 am
Sounds like a plan. I hope you build in the flexibilty described above, eg by Tim. Is this for CiviBanking?
Co-author of Using CiviCRM https://www.packtpub.com/using-civicrm/book

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: Context required in civicrm_pre and civicrm_post hook
May 17, 2013, 06:01:02 am
This is not for CiviBanking, it is for an existing synchronization with CiviCRM that we are upgrading to 4.3 and api V3. Yes, I will certainly build in the flexibility as Tim suggested, that makes perfect sense. We need to be flexible and the assumption that synchronization should not be done works only in my install. It might be a bit of a project though.....but the first step is the description :-)
Consultant/project manager at EEatWork and CiviCooP (http://www.civicoop.org/)

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: Context required in civicrm_pre and civicrm_post hook
May 23, 2013, 11:02:02 am
Okay,
this is what I have just done in some testing for synchronizing phone numbers:

First I added the hook_context param to my specific API, which in turn calls the core API:
Code: [Select]
$civiparms = array(
"contact_id"        =>  $contact_id,
"location_type_id"  =>  $location_type_id,
"is_primary"        =>  $is_primary,
"phone_type_id"     =>  $phone_type_id,
"phone"             =>  $phone,
"version" =>  3);
        if ( isset( $inparms['hook_context'] ) ) {
            $civiparms['hook_context'] = $inparms['hook_context'];
        } else {
            $civiparms['hook_context'] = "dgwapi.no_sync";
        }
$res_phone = civicrm_api('Phone', 'Create', $civiparms);

Next I have added a  few lines with the hookContext to the CRM/Core/BAO/Phone.php:
Code: [Select]
  static function add(&$params) {
    $hook = empty($params['id']) ? 'create' : 'edit';
    if ( $params['hook_context'] ) {
        $hookContext = $params['hook_context'];
        unset( $params['hook_context'] );
    } else {
        $hookContext = "core";
    }
    CRM_Utils_Hook::pre($hook, 'Phone', CRM_Utils_Array::value('id', $params), $params, $hookContext);

    $phone = new CRM_Core_DAO_Phone();
    $phone->copyValues($params);
    $phone->save();

    CRM_Utils_Hook::post($hook, 'Phone', $phone->id, $phone, $hookContext );
    return $phone;
  }

I have made a small adjustment to the CRM/Utils/Hook.php:
Code: [Select]
  static function pre($op, $objectName, $id, &$params, $hookContext) {
      /*
       *
       */
      $hookContextObjects = array( "Phone", "Email", "Address". "Individual", "Organization" );
      if ( in_array( $objectName, $hookContextObjects ) ) {
        return self::singleton()->invoke(5, $op, $objectName, $id, $params, $hookContext, 'civicrm_pre');
      } else {
          return self::singleton()->invoke(4, $op, $objectName, $id, $params, $op, 'civicrm_pre' );
      }
  }

And now I can check in my hook civicrm_pre if a call is from my specific api or from any other spot:

Code: [Select]
function sync_civicrm_pre( $op, $objectName, $objectId, &$objectRef, $hookContext ) {
    /*
     * only for some objects
     */
    $syncedObjects = array( "Individual", "Organization", "Address", "Email", "Phone" );
    /*
     * only if op is not create (handled in sync_civicrm_post)
     */
    if ( $op != "create" ) {
        /*
         * skip execution if hook originates from API De Goede Woning
         */
        if ( $hookContext != "dgwapi.no_sync" ) {
            if (in_array( $objectName, $syncedObjects ) ) {

What do you think so far? If I am going to tackle this in core I would add the hookContext as an option for the api rather than as a separate param.
Consultant/project manager at EEatWork and CiviCooP (http://www.civicoop.org/)

xavier

  • Forum Godess / God
  • I’m (like) Lobo ;)
  • *****
  • Posts: 4453
  • Karma: 161
    • Tech To The People
  • CiviCRM version: yes probably
  • CMS version: drupal
Re: Context required in civicrm_pre and civicrm_post hook
June 12, 2013, 09:29:18 am
Hi,

At the sprint in adreche, I brainstormed it with Tim and Erawat.

We started by introducing a CRM_Core_Container where you could push and query contexts.
So the core would set the context in page run (eg. the name of the class) and do the same for the forum.

Each extension or custom code could do the same and use their own specific stack. However, all the real life examples I could think of needed to handle their own stack as the generic core one wouldn't have been enough.

And so we came back to the simpliest stack:

$GLOBALS["extension_name"]["key_for_context"]= "whatever floats your boat";

and happily pollute the global namespace, as the php gods intended.

X+

P.S. More specifically, it would introduce another difference between the 4.3 and 4.4 extensions and compatibility issues for a benefit we didn't identify as important enough. We could be convinced otherwise by a strong counterargument and real example, patch welcome and all that jazz.
« Last Edit: June 13, 2013, 12:09:37 am by xavier »
-Hackathon and data journalism about the European parliament 24-26 jan. Watch out the result

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: Context required in civicrm_pre and civicrm_post hook
June 12, 2013, 11:27:25 pm
Makes sense, I can live with that as a solution.
Consultant/project manager at EEatWork and CiviCooP (http://www.civicoop.org/)

Pages: [1]
  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion »
  • APIs and Hooks (Moderator: Donald Lobo) »
  • Context required in civicrm_pre and civicrm_post hook

This forum was archived on 2017-11-26.