How to use the custom Apigee batch functions

Not applicable

We have a custom content type called a publishing form, whenever the form is updated/created a call is made to an outside service to retrieve some metadata concerning the owner of the API. Because the outside service adds a delay to the process, we decided to make the call through Drupal's batch process. However, Apigee's profile adds an animation to the batch process that we do not know how to use.

Can someone provide guidance for using this?

Here is some code showing how we've implemented the batch system:

<?php
$batch = array(
    'title' => t('API Publishing Form update'),
    'file' => drupal_get_path('module', 'custom_rules_http_client'),
    'init_message' => t('Updating publishing form(s)'),
    'progress_message' => t('Processed @current out of @total.'),
    'finished' => 'smartdocs_render_finished', //\profiles\apigee\modules\custom\devconnect\smartdocs\batch\smartdocs.render.inc
    'error_message' => t('Updating API Publishing Form %nid has encountered an error.', array('%nid' => $nid)),
    'operations' => array('update_api_publishing_form', array( $nid, $data )),
  );

  batch_set($batch);

custom_rules_http_client code:

<?php
function update_api_publishing_form($nid, $data, &$context = null){
  if (is_null($context)) {
    $context = array();
  }
  if (is_string($data)) {
    $data = simplexml_load_string($data);
  }
  //Use entity wrapper to provide helper functions such as set and save
  $wrapper = entity_metadata_wrapper('node', $nid);
  If (isset($wrapper)){
    //map the fields from the data to the node
    testAndSet ($wrapper, "field_custom_data", $data);
    
    try { 
    //save changes to database
    $wrapper->save();
    }
    catch (Exception $e) {
      $context['message'] = 'batch process completed with some errors.';
      return;
    }
  }
  
  $context['message'] = 'Finished updating the API Publishing Form';
  $context['results'] = 'Finished updating the API Publishing Form';
  return;
}

/**
 * Custom function to test that both variables exist before setting in memory
 */
function testAndSet ($wrapper, $var_name, $data) {
  if (isset ($wrapper->$var_name)) {
    $wrapper->$var_name = isset ($data) ? "" . $data . "" : "";
  }
  return;
}
Solved Solved
0 2 859
1 ACCEPTED SOLUTION

Not applicable

I did not post enough context to catch the real problem. The dev portal did not have a custom batch animation, it was the Drupal default animation. The real problem was caused by a rule used to call the batch process only when the API Publishing form was modified. Unfortunately, this function updates the Publishing form which would trigger the rule again and go into an infinite recursive loop.

Silly mistakes.....

But just in case this helps others, I also needed to use the context variable to save the current data being used in the batch process. This is the only way the data can be retained if Drupal pauses the process and resumes it later.

<?php
function _my_batch($nid) {
  $data = _get_data($args);//Some well formed XML string returned
  $batch = _initialize_batch();
  array_push( $batch['operations'], array('update_api_publishing_form', array( $nid, $data )) );

  batch_set($batch);
  batch_process($_SERVER['REQUEST_URI']);
}

/**
 * Custom function to create and set a batch process
 * This does not set the $operations variable
 */
function _initialize_batch(){
  $batch = array(
    'title' => t('Retrieving data'),
    'file' => drupal_get_path('module', 'my_module'),
    //'progressive' => false, //Toggles the progress bar page?
    'init_message' => t('Updating publishing form(s)'),
    'progress_message' => t('Processed @current out of @total.'),
    'finished' => 'smartdocs_render_finished', //\profiles\apigee\modules\custom\devconnect\smartdocs\batch\smartdocs.render.inc
    'error_message' => t('Updating API Publishing Form has encountered an error.'),
    'operations' => array(),
  );
  return $batch;
}

/**
 * Custom function
 * Parse data from the previous call
 * Retrieve API publishing form from database
 * Update the node
 * save changes
 */
function update_api_publishing_form($nid, $data, &$context = array()){
  if(!isset($context['sandbox']['progress'])){
    $context['sandbox']['progress'] = 0;
    $context['sandbox']['total'] = 1;//number of fields to update
  }
  
  //Load the string as a simple xml resource and then convert to STDClass object
  //Reference http://stackoverflow.com/questions/1584725/quickly-convert-simplexmlobject-to-stdclass
  $context['sandbox']['data'] = $data;
  if (is_string($data)) {
    $context['sandbox']['data'] = simplexml_load_string($context['sandbox']['data']);
  } 
  if (!is_object($context['sandbox']['data'])) {
    $context['sandbox']['data'] = json_decode(json_encode($context['sandbox']['data']));
  }
  
  //Use entity wrapper to provide helper functions such as set and save
  $context['sandbox']['wrapper'] = entity_metadata_wrapper('node', $nid);
  If (isset($context['sandbox']['wrapper'])){
    
    //map the fields from the data to the node
    testAndSet ($context, "field_custom_data", "some_xml_data");
    
    try { 
    //save changes to database
      $context['sandbox']['wrapper']->save();
    }
    catch (Exception $e) {
      $context['message'][] = 'Batch process completed with some errors.';
      custom_watchdog('Batch exception', $e);//Log the error
      return;
    }
  }
  
  $context['message'][] = 'Finished updating the API Publishing Form';
  $context['results'][] = 'Finished updating the API Publishing Form';
  $context['finished'] = $context['sandbox']['progress']/$context['sandbox']['total'];
}
 
/**
 * Custom function to test that both variables exist before setting in memory
 */
function testAndSet (&$context, $wrapperVar, $responseVar) {
  if (isset ($context['sandbox']['wrapper']->$wrapperVar)) {
    if (is_object($context['sandbox']['data']->$responseVar) or empty($context['sandbox']['data']->$responseVar)) {
      $context['sandbox']['wrapper']->$wrapperVar = "";
    } else {
      try{
        $context['sandbox']['wrapper']->$wrapperVar = isset ($context['sandbox']['data']->$responseVar) ? "" . $context['sandbox']['data']->$responseVar . "" : "";
      } catch (Exception $e) {
        $exception_mess = array(
          'e' => $e,
          'wrapperVar' => $context['sandbox']['wrapper']->$wrapperVar,
          'responseVar' => $context['sandbox']['data']->$responseVar,
        );
        
        custom_watchdog('testAndSet exception', $exception_mess);
        throw $e;
      }
    }
  }  
  $context['sandbox']['progress']++;
}

View solution in original post

2 REPLIES 2

Not applicable

I did not post enough context to catch the real problem. The dev portal did not have a custom batch animation, it was the Drupal default animation. The real problem was caused by a rule used to call the batch process only when the API Publishing form was modified. Unfortunately, this function updates the Publishing form which would trigger the rule again and go into an infinite recursive loop.

Silly mistakes.....

But just in case this helps others, I also needed to use the context variable to save the current data being used in the batch process. This is the only way the data can be retained if Drupal pauses the process and resumes it later.

<?php
function _my_batch($nid) {
  $data = _get_data($args);//Some well formed XML string returned
  $batch = _initialize_batch();
  array_push( $batch['operations'], array('update_api_publishing_form', array( $nid, $data )) );

  batch_set($batch);
  batch_process($_SERVER['REQUEST_URI']);
}

/**
 * Custom function to create and set a batch process
 * This does not set the $operations variable
 */
function _initialize_batch(){
  $batch = array(
    'title' => t('Retrieving data'),
    'file' => drupal_get_path('module', 'my_module'),
    //'progressive' => false, //Toggles the progress bar page?
    'init_message' => t('Updating publishing form(s)'),
    'progress_message' => t('Processed @current out of @total.'),
    'finished' => 'smartdocs_render_finished', //\profiles\apigee\modules\custom\devconnect\smartdocs\batch\smartdocs.render.inc
    'error_message' => t('Updating API Publishing Form has encountered an error.'),
    'operations' => array(),
  );
  return $batch;
}

/**
 * Custom function
 * Parse data from the previous call
 * Retrieve API publishing form from database
 * Update the node
 * save changes
 */
function update_api_publishing_form($nid, $data, &$context = array()){
  if(!isset($context['sandbox']['progress'])){
    $context['sandbox']['progress'] = 0;
    $context['sandbox']['total'] = 1;//number of fields to update
  }
  
  //Load the string as a simple xml resource and then convert to STDClass object
  //Reference http://stackoverflow.com/questions/1584725/quickly-convert-simplexmlobject-to-stdclass
  $context['sandbox']['data'] = $data;
  if (is_string($data)) {
    $context['sandbox']['data'] = simplexml_load_string($context['sandbox']['data']);
  } 
  if (!is_object($context['sandbox']['data'])) {
    $context['sandbox']['data'] = json_decode(json_encode($context['sandbox']['data']));
  }
  
  //Use entity wrapper to provide helper functions such as set and save
  $context['sandbox']['wrapper'] = entity_metadata_wrapper('node', $nid);
  If (isset($context['sandbox']['wrapper'])){
    
    //map the fields from the data to the node
    testAndSet ($context, "field_custom_data", "some_xml_data");
    
    try { 
    //save changes to database
      $context['sandbox']['wrapper']->save();
    }
    catch (Exception $e) {
      $context['message'][] = 'Batch process completed with some errors.';
      custom_watchdog('Batch exception', $e);//Log the error
      return;
    }
  }
  
  $context['message'][] = 'Finished updating the API Publishing Form';
  $context['results'][] = 'Finished updating the API Publishing Form';
  $context['finished'] = $context['sandbox']['progress']/$context['sandbox']['total'];
}
 
/**
 * Custom function to test that both variables exist before setting in memory
 */
function testAndSet (&$context, $wrapperVar, $responseVar) {
  if (isset ($context['sandbox']['wrapper']->$wrapperVar)) {
    if (is_object($context['sandbox']['data']->$responseVar) or empty($context['sandbox']['data']->$responseVar)) {
      $context['sandbox']['wrapper']->$wrapperVar = "";
    } else {
      try{
        $context['sandbox']['wrapper']->$wrapperVar = isset ($context['sandbox']['data']->$responseVar) ? "" . $context['sandbox']['data']->$responseVar . "" : "";
      } catch (Exception $e) {
        $exception_mess = array(
          'e' => $e,
          'wrapperVar' => $context['sandbox']['wrapper']->$wrapperVar,
          'responseVar' => $context['sandbox']['data']->$responseVar,
        );
        
        custom_watchdog('testAndSet exception', $exception_mess);
        throw $e;
      }
    }
  }  
  $context['sandbox']['progress']++;
}

We are in a procedure to include third Datacenter as a DR . Anyway we don't know of how the "LDAP_PEER" property in the config. document ought to be arrangement with the goal that the LDAP on every one of the 3 LDAP for hire an animation studio company hubs are in a state of harmony. Would you be able to please post the config record utilized by you in the wake of concealing the touchy information? Would be an incredible assistance.