Answers.Body: <p>The participant create in <code>set_kavo_state()</code> triggers your post hook again which then calls <code>set_kavo_state()</code> etc.  You need to determine whether the post hook is being called just to update the <code>$kavo_status_field</code> and <code>$kavo_message_field</code> fields - and therefore not set up another callback to <code>set_kavo_state()</code>.</p>
  
  <p>Do you actually need to call your external API for participant edits?  If you could limit the post hook to only trigger on 'create' you would avoid the loop. </p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-09-22T08:48:13.553Z
Answers.Text: The external api needs to be called when participants are edited, and their kavo fields need to be set based on the api response.
  I know the call to set the kavo fiels is the reason for getting in the loop, I was wondering wether there was a way to set them without getting back in the post hook.
Answers.UserDisplayName: joost
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-04-20T12:16:53.220Z
Answers.Text: I think that if you check your request in the post hook you can determine if you are coming in from the API or not?
Answers.UserDisplayName: ErikH - CiviCooP
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-09-22T08:13:05.567Z
Answers.LastActivityDate: 2017-09-22T08:13:05.567Z
Answers.UserDisplayName: Aidan
Answers.Body: <p>If you are using Drupal, you can use the Drupal static cache infrastructure to break the cycle. In this particular example, the static cache is only available for one page load / http request. You can set a database cache as well, see References below for detailed explanation and instructions</p>
  
  <pre><code>function set_kavo_state($participant_id, $state, $message='success'){
    $stop = &amp;drupal_static(__FUNCTION__);
    // could use more logic in this conditional if need be ... but at least you will know if you've come back a second time...
    if (!isset($stop)) {
      $kavo_status_field = CRM_Kavo_Field::KAVO_PARTICIPANT_STATUS();
      $kavo_message_field = CRM_Kavo_Field::KAVO_PARTICIPANT_MESSAGE();
      civicrm_api3('Participant', 'create', array(
        'id' =&gt; $participant_id,
        $kavo_status_field =&gt; $state,
        $kavo_message_field =&gt; $message
      ));
      $stop = 1;
    }
  }
  </code></pre>
  
  <p>References:
  <a href="https://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/drupal_static/7.x" rel="nofollow noreferrer">Drupal API documentation</a>
  <a href="https://www.lullabot.com/articles/a-beginners-guide-to-caching-data-in-drupal-7" rel="nofollow noreferrer">A Beginner's Guide to Caching Data in Drupal 7</a></p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-11-17T02:09:44.420Z
Answers.LastActivityDate: 2018-11-17T02:09:44.420Z
Answers.UserDisplayName: jackrabbithanna
Answers.Body: <p>You have two choices:</p>
  
  <ul>
  <li>Use <code>hook_civicrm_pre</code> instead of <code>hook_civirm_post</code>.  This isn't ideal because it's synchronous and will slow down your writes.</li>
  <li>Since you're updating custom fields only, continue to use <code>hook_civicrm_post</code>, but instead of calling <code>Participant.create</code>, call <code>CustomValue.create</code>, which won't trigger the post hook a second time. </li>
  </ul>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-08-18T19:04:12.057Z
Answers.LastActivityDate: 2018-08-18T19:04:12.057Z
Answers.UserDisplayName: Jon G - Megaphone Tech
Body: <p>We have a post hook that sends some data to an external api when a participant is created or edited.</p>
  
  <p><code>function kavo_civicrm_post($op, $objectName, $objectId, &amp;$objectRef) {
    if (($op == 'create' || $op == 'edit') &amp;&amp; $objectName == 'Participant') {</code></p>
  
  <p>Based on the response of that api a custom field on the response of that API a couple of custom fields on the participant should be set. This is done using the php api, but results in a loop with the post hook being called, even when following the add_callback instructions in the <a href="https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_post/" rel="nofollow noreferrer">post hook documentation</a>.</p>
  
  <p><code>try {
                 civicrm_api3('Kavo', 'createparticipant', ['participant_id' =&gt; $objectId]);
                 $successState = CRM_Kavo_Status::KAVO_ATTENDED();
                 CRM_Core_Transaction::addCallback(CRM_Core_Transaction::PHASE_POST_COMMIT, 'set_kavo_state', [$objectId, $successState]);
              } catch (CiviCRM_API3_Exception $ex) {
                 $contact = $worker-&gt;getContact($participant);
                 CRM_Core_Session::setStatus($ex-&gt;getMessage(), ts("Failed sending participant %1 to KAVO.", [1 =&gt; $contact['display_name']]), 'error');
                 $failedState = CRM_Kavo_Status::KAVO_FAILED();
                 CRM_Core_Transaction::addCallback(CRM_Core_Transaction::PHASE_POST_COMMIT, 'set_kavo_state', [$objectId, $failedState, $ex-&gt;getMessage()]);
              }</code></p>
  
  <p><code>function set_kavo_state($participant_id, $state, $message='success'){
    $kavo_status_field = CRM_Kavo_Field::KAVO_PARTICIPANT_STATUS();
    $kavo_message_field = CRM_Kavo_Field::KAVO_PARTICIPANT_MESSAGE();
    civicrm_api3('Participant', 'create', array(
      'id' =&gt; $participant_id,
      $kavo_status_field =&gt; $state,
      $kavo_message_field =&gt; $message
    ));
  }
  </code></p>
  
  <p>The kavo create_participant call does our call to the external api
   Is there another way to edit the participant being edited in a post hook?</p>
  
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-09-21T11:35:28.723Z
Comments.Text: I am not clear on what you are asking, can you give a little more detail? I think I understand (and know the problem) but I am not sure.....
Comments.UserDisplayName: ErikH - CiviCooP
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-09-21T11:47:01.950Z
Comments.Text: In a post hook we send a request to an external api. This post hook is limited to working on particapants on edit or create. Depending on the succes of the api call I want to set a costum field on the participant. I will edit some code in the original question to clarify.
Comments.UserDisplayName: joost
Tags: <api><hooks>
Title: post hook edit entity
ThreadText: # post hook edit entity
  
  (Asked by: username_0 on 2017-09-21)
  
  We have a post hook that sends some data to an external api when a participant is created or edited.
  
  `function kavo_civicrm_post($op, $objectName, $objectId, &$objectRef) {
  if (($op == 'create' || $op == 'edit') && $objectName == 'Participant') {`
  
  Based on the response of that api a custom field on the response of that API a couple of custom fields on the participant should be set. This is done using the php api, but results in a loop with the post hook being called, even when following the add\_callback instructions in the [post hook documentation](https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_post/).
  
  `try {
  civicrm_api3('Kavo', 'createparticipant', ['participant_id' => $objectId]);
  $successState = CRM_Kavo_Status::KAVO_ATTENDED();
  CRM_Core_Transaction::addCallback(CRM_Core_Transaction::PHASE_POST_COMMIT, 'set_kavo_state', [$objectId, $successState]);
  } catch (CiviCRM_API3_Exception $ex) {
  $contact = $worker->getContact($participant);
  CRM_Core_Session::setStatus($ex->getMessage(), ts("Failed sending participant %1 to KAVO.", [1 => $contact['display_name']]), 'error');
  $failedState = CRM_Kavo_Status::KAVO_FAILED();
  CRM_Core_Transaction::addCallback(CRM_Core_Transaction::PHASE_POST_COMMIT, 'set_kavo_state', [$objectId, $failedState, $ex->getMessage()]);
  }`
  
  `function set_kavo_state($participant_id, $state, $message='success'){
  $kavo_status_field = CRM_Kavo_Field::KAVO_PARTICIPANT_STATUS();
  $kavo_message_field = CRM_Kavo_Field::KAVO_PARTICIPANT_MESSAGE();
  civicrm_api3('Participant', 'create', array(
  'id' => $participant_id,
  $kavo_status_field => $state,
  $kavo_message_field => $message
  ));
  }`
  
  The kavo create\_participant call does our call to the external api
  Is there another way to edit the participant being edited in a post hook?
  
  **Tags:** api, hooks
  
  > **Comments:**
  > **username_1**: I am not clear on what you are asking, can you give a little more detail? I think I understand (and know the problem) but I am not sure.....  
  > **username_0**: In a post hook we send a request to an external api. This post hook is limited to working on particapants on edit or create. Depending on the succes of the api call I want to set a costum field on the participant. I will edit some code in the original question to clarify.  
  
  ---
  
  ## 3 answers
  
  ### Answer by username_2 on 2017-09-22. Score: 1
  
  The participant create in `set_kavo_state()` triggers your post hook again which then calls `set_kavo_state()` etc. You need to determine whether the post hook is being called just to update the `$kavo_status_field` and `$kavo_message_field` fields - and therefore not set up another callback to `set_kavo_state()`.
  
  Do you actually need to call your external API for participant edits? If you could limit the post hook to only trigger on 'create' you would avoid the loop.
  
  > **Comments:**
  > **username_0**: The external api needs to be called when participants are edited, and their kavo fields need to be set based on the api response. I know the call to set the kavo fiels is the reason for getting in the loop, I was wondering wether there was a way to set them without getting back in the post hook.  
  > **username_1**: I think that if you check your request in the post hook you can determine if you are coming in from the API or not?  
  
  ---
  
  ### Answer by username_3 on 2018-11-17. Score: 1
  
  If you are using Drupal, you can use the Drupal static cache infrastructure to break the cycle. In this particular example, the static cache is only available for one page load / http request. You can set a database cache as well, see References below for detailed explanation and instructions
  
  ```
  function set_kavo_state($participant_id, $state, $message='success'){
    $stop = &drupal_static(__FUNCTION__);
    // could use more logic in this conditional if need be ... but at least you will know if you've come back a second time...
    if (!isset($stop)) {
      $kavo_status_field = CRM_Kavo_Field::KAVO_PARTICIPANT_STATUS();
      $kavo_message_field = CRM_Kavo_Field::KAVO_PARTICIPANT_MESSAGE();
      civicrm_api3('Participant', 'create', array(
        'id' => $participant_id,
        $kavo_status_field => $state,
        $kavo_message_field => $message
      ));
      $stop = 1;
    }
  }
  
  ```
  
  References:
  [Drupal API documentation](https://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/drupal_static/7.x)
  [A Beginner's Guide to Caching Data in Drupal 7](https://www.lullabot.com/articles/a-beginners-guide-to-caching-data-in-drupal-7)
  
  
  ---
  
  ### Answer by username_4 on 2018-08-18. Score: 1
  
  You have two choices:
  
  * Use `hook_civicrm_pre` instead of `hook_civirm_post`. This isn't ideal because it's synchronous and will slow down your writes.
  * Since you're updating custom fields only, continue to use `hook_civicrm_post`, but instead of calling `Participant.create`, call `CustomValue.create`, which won't trigger the post hook a second time.
  
  
  ---
  
  