|  | @@ -186,14 +186,25 @@ function tripal_remove_site($record_id) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  | - * Retreives the full Hydra documentattion for the remote Tripal site.
 | 
	
		
			
				|  |  | + * Makes a request to the "content"service of a remote Tripal web site.
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  | - * When passed a site_id from the tripal_sites table the full
 | 
	
		
			
				|  |  | - * site's document service is returned in json format
 | 
	
		
			
				|  |  | + * @param $site_id
 | 
	
		
			
				|  |  | + *   The numeric site ID for the remote Tripal site.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @param $query
 | 
	
		
			
				|  |  | + *   The query string. This string is added to the URL for the remote
 | 
	
		
			
				|  |  | + *   website.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @return
 | 
	
		
			
				|  |  | + *   The JSON response formatted in a PHP array or FALSE if a problem occured.
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -function tripal_get_remote_site_doc($site_id) {
 | 
	
		
			
				|  |  | +function tripal_query_remote_site($site_id, $query) {
 | 
	
		
			
				|  |  | +  $ctype = $query;
 | 
	
		
			
				|  |  | +  $qdata = '';
 | 
	
		
			
				|  |  | +  if (preg_match('/\?/', $query)) {
 | 
	
		
			
				|  |  | +    list($ctype, $qdata) = explode('?', $query);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  // Get the site url from the tripal_sites table.
 | 
	
		
			
				|  |  |    if ($site_id) {
 | 
	
		
			
				|  |  |      $remote_site = db_select('tripal_sites', 'ts')
 | 
	
		
			
				|  |  |        ->fields('ts')
 | 
	
	
		
			
				|  | @@ -206,10 +217,12 @@ function tripal_get_remote_site_doc($site_id) {
 | 
	
		
			
				|  |  |    $ws_version = $remote_site->version;
 | 
	
		
			
				|  |  |    $ws_url = $remote_site->url;
 | 
	
		
			
				|  |  |    $ws_url = trim($ws_url, '/');
 | 
	
		
			
				|  |  | -  $ws_url .= '/web-services/doc/' . $ws_version;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // Build and make the request.
 | 
	
		
			
				|  |  | -  $options = [];
 | 
	
		
			
				|  |  | +  $ws_url .= '/web-services/content/' . $ws_version . '/' . $ctype;
 | 
	
		
			
				|  |  | +  // Build the Query and make and substitions needed.
 | 
	
		
			
				|  |  | +  //dpm($ws_url . '?' . $query);
 | 
	
		
			
				|  |  | +  $options = array(
 | 
	
		
			
				|  |  | +    'data' => $qdata,
 | 
	
		
			
				|  |  | +  );
 | 
	
		
			
				|  |  |    $data = drupal_http_request($ws_url, $options);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (!$data) {
 | 
	
	
		
			
				|  | @@ -222,8 +235,8 @@ function tripal_get_remote_site_doc($site_id) {
 | 
	
		
			
				|  |  |    // connection error (not a Tripal web servcies error).
 | 
	
		
			
				|  |  |    if (property_exists($data, 'error')) {
 | 
	
		
			
				|  |  |      tripal_report_error('tripal_ws', TRIPAL_ERROR,
 | 
	
		
			
				|  |  | -        'Web Services error on remote site: %error.',
 | 
	
		
			
				|  |  | -        array('%error' => $data->error));
 | 
	
		
			
				|  |  | +        'Remote web Services reports the following error: !error. Using URL: !url',
 | 
	
		
			
				|  |  | +        array('!error' => $error, '!url' => $ws_url));
 | 
	
		
			
				|  |  |      return FALSE;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -234,8 +247,8 @@ function tripal_get_remote_site_doc($site_id) {
 | 
	
		
			
				|  |  |    if (array_key_exists('error', $data)) {
 | 
	
		
			
				|  |  |      $error = '</pre>' . print_r($data['error'], TRUE) . '</pre>';
 | 
	
		
			
				|  |  |      tripal_report_error('tripal_ws', TRIPAL_ERROR,
 | 
	
		
			
				|  |  | -        'Web Services error on remote site: %error.',
 | 
	
		
			
				|  |  | -        array('%error' => $error));
 | 
	
		
			
				|  |  | +        'Tripal remote web services reports the following error: !error. Using URL: !url',
 | 
	
		
			
				|  |  | +        array('!error' => $error, '!url' => $ws_url));
 | 
	
		
			
				|  |  |      return FALSE;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -243,40 +256,113 @@ function tripal_get_remote_site_doc($site_id) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  | - * Makes a request to a remote Tripal web services site.
 | 
	
		
			
				|  |  | + * Retrieves the JSON-LD context for any remote Tripal web service.
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  | - * @param $query
 | 
	
		
			
				|  |  | - *   The query string. This string is added to the URL for the remote
 | 
	
		
			
				|  |  | - *   website.
 | 
	
		
			
				|  |  | + * @param $context_url
 | 
	
		
			
				|  |  | + *   The Full URL for the context file on the remote Tripal site. This URL
 | 
	
		
			
				|  |  | + *   can be found in the '@context' key of any response from a remote Tripal
 | 
	
		
			
				|  |  | + *   web services call.
 | 
	
		
			
				|  |  | + * @param $cache_id
 | 
	
		
			
				|  |  | + *   A unique ID for caching of this context result to speed furture
 | 
	
		
			
				|  |  | + *   queries.
 | 
	
		
			
				|  |  | + * @return
 | 
	
		
			
				|  |  | + *   The JSON-LD context mapping array, or FALSE if the context could not
 | 
	
		
			
				|  |  | + *   be retrieved.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +function tripal_get_remote_context($context_url, $cache_id) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (!$context_url) {
 | 
	
		
			
				|  |  | +    throw new Exception('PLease provide a context_url for the tripal_get_remote_context function.');
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (!$cache_id) {
 | 
	
		
			
				|  |  | +    throw new Exception('PLease provide unique $cache_id for the tripal_get_remote_context function.');
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if ($cache = cache_get($cache_id)) {
 | 
	
		
			
				|  |  | +    return $cache->data;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  $context = drupal_http_request($context_url);
 | 
	
		
			
				|  |  | +  if (!$context) {
 | 
	
		
			
				|  |  | +    tripal_report_error('tripal_ws', TRIPAL_ERROR,
 | 
	
		
			
				|  |  | +        'There was a poblem retrieving the context from the remote site: !context_url.',
 | 
	
		
			
				|  |  | +        array('!context_url' => $context_url));
 | 
	
		
			
				|  |  | +    return FALSE;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  $context = drupal_json_decode($context->data);
 | 
	
		
			
				|  |  | +  $context = $context['@context'];
 | 
	
		
			
				|  |  | +  cache_set($cache_id, $context);
 | 
	
		
			
				|  |  | +  return $context;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * Retrieves the JSON-LD context for a bundle or field on a remote Tripal site.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * The $site_id, $bundle_accession and $field_accession variables are not
 | 
	
		
			
				|  |  | + * needed to retrieve the context, but are used for caching the context to
 | 
	
		
			
				|  |  | + * make subsequent calls execute faster.  This function is meant to be used
 | 
	
		
			
				|  |  | + * only for the 'content' service provided by Tripal.
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  | + * @param $site_id
 | 
	
		
			
				|  |  | + *    The numeric site ID for the remote Tripal site.
 | 
	
		
			
				|  |  | + * @param $context_url
 | 
	
		
			
				|  |  | + *   The Full URL for the context file on the remote Tripal site. This URL
 | 
	
		
			
				|  |  | + *   can be found in the '@context' key of any response from a remote Tripal
 | 
	
		
			
				|  |  | + *   web services call.
 | 
	
		
			
				|  |  | + * @param $bundle_accession
 | 
	
		
			
				|  |  | + *   The controlled vocabulary term accession for the content type
 | 
	
		
			
				|  |  | + *   on the remote Tripal site.
 | 
	
		
			
				|  |  | + * @param $field_accession
 | 
	
		
			
				|  |  | + *   The controlled vocabulary term accession for the property (i.e. field) of
 | 
	
		
			
				|  |  | + *   the Class (i.e. content type).
 | 
	
		
			
				|  |  |   * @return
 | 
	
		
			
				|  |  | - *   The JSON response formatted in a PHP array or FALSE if a problem occured.
 | 
	
		
			
				|  |  | + *   The JSON-LD context mapping array.
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -function tripal_query_remote_site($site_id, $query) {
 | 
	
		
			
				|  |  | -  $ctype = $query;
 | 
	
		
			
				|  |  | -  $qdata = '';
 | 
	
		
			
				|  |  | -  if (preg_match('/\?/', $query)) {
 | 
	
		
			
				|  |  | -    list($ctype, $qdata) = explode('?', $query);
 | 
	
		
			
				|  |  | +function tripal_get_remote_content_context($site_id, $context_url, $bundle_accession, $field_accession = '') {
 | 
	
		
			
				|  |  | +  $cache_id = substr('trp_ws_context_' . $site_id . '-' . $bundle_accession . '-' . $field_accession, 0, 254);
 | 
	
		
			
				|  |  | +  $context = tripal_get_remote_context($context_url, $cache_id);
 | 
	
		
			
				|  |  | +  return $context;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * Retrieves the API documentation for a remote Tripal web service.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @param $site_id
 | 
	
		
			
				|  |  | + *   The numeric site ID for the remote Tripal site.
 | 
	
		
			
				|  |  | + * @return
 | 
	
		
			
				|  |  | + *   The vocabulary of a remote Tripal web service, or FALSE if an error
 | 
	
		
			
				|  |  | + *   occured.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +function tripal_get_remote_API_doc($site_id) {
 | 
	
		
			
				|  |  | +  $site_doc = '';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (!$site_id) {
 | 
	
		
			
				|  |  | +    throw new Exception('PLease provide a numeric site ID for the tripal_get_remote_API_doc function.');
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if ($site_id) {
 | 
	
		
			
				|  |  | -    $remote_site = db_select('tripal_sites', 'ts')
 | 
	
		
			
				|  |  | -      ->fields('ts')
 | 
	
		
			
				|  |  | -      ->condition('ts.id', $site_id)
 | 
	
		
			
				|  |  | -      ->execute()
 | 
	
		
			
				|  |  | -      ->fetchObject();
 | 
	
		
			
				|  |  | +  $cache_name = 'trp_ws_doc_' . $site_id;
 | 
	
		
			
				|  |  | +  if ($cache = cache_get($cache_name)) {
 | 
	
		
			
				|  |  | +    return $cache->data;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Get the site url from the tripal_sites table.
 | 
	
		
			
				|  |  | +  $remote_site = db_select('tripal_sites', 'ts')
 | 
	
		
			
				|  |  | +    ->fields('ts')
 | 
	
		
			
				|  |  | +    ->condition('ts.id', $site_id)
 | 
	
		
			
				|  |  | +    ->execute()
 | 
	
		
			
				|  |  | +    ->fetchObject();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (!$remote_site) {
 | 
	
		
			
				|  |  | +    throw new Exception(t('Cannot find a remote site with id: "!id"', array('!id' => $site_id)));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Build the URL to the remote web services.
 | 
	
		
			
				|  |  |    $ws_version = $remote_site->version;
 | 
	
		
			
				|  |  |    $ws_url = $remote_site->url;
 | 
	
		
			
				|  |  |    $ws_url = trim($ws_url, '/');
 | 
	
		
			
				|  |  | -  $ws_url .= '/web-services/content/' . $ws_version . '/' . $ctype;
 | 
	
		
			
				|  |  | -  // Build the Query and make and substitions needed.
 | 
	
		
			
				|  |  | -  //dpm($ws_url . '?' . $query);
 | 
	
		
			
				|  |  | -  $options = array(
 | 
	
		
			
				|  |  | -    'data' => $qdata,
 | 
	
		
			
				|  |  | -  );
 | 
	
		
			
				|  |  | +  $ws_url .= '/web-services/doc/' . $ws_version;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Build and make the request.
 | 
	
		
			
				|  |  | +  $options = [];
 | 
	
		
			
				|  |  |    $data = drupal_http_request($ws_url, $options);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (!$data) {
 | 
	
	
		
			
				|  | @@ -289,22 +375,392 @@ function tripal_query_remote_site($site_id, $query) {
 | 
	
		
			
				|  |  |    // connection error (not a Tripal web servcies error).
 | 
	
		
			
				|  |  |    if (property_exists($data, 'error')) {
 | 
	
		
			
				|  |  |      tripal_report_error('tripal_ws', TRIPAL_ERROR,
 | 
	
		
			
				|  |  | -        'Web Services error on remote site: %error.',
 | 
	
		
			
				|  |  | -        array('%error' => $data->error));
 | 
	
		
			
				|  |  | +        'Remote web services document reports the following error: !error. Using URL: !url',
 | 
	
		
			
				|  |  | +      array('!error' => $error, '!url' => $ws_url));
 | 
	
		
			
				|  |  |      return FALSE;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // We got a response, so convert it to a PHP array.
 | 
	
		
			
				|  |  | -  $data = drupal_json_decode($data->data);
 | 
	
		
			
				|  |  | +  $site_doc = drupal_json_decode($data->data);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Check if there was a Tripal Web Services error.
 | 
	
		
			
				|  |  |    if (array_key_exists('error', $data)) {
 | 
	
		
			
				|  |  |      $error = '</pre>' . print_r($data['error'], TRUE) . '</pre>';
 | 
	
		
			
				|  |  |      tripal_report_error('tripal_ws', TRIPAL_ERROR,
 | 
	
		
			
				|  |  | -        'Web Services error on remote site: %error.',
 | 
	
		
			
				|  |  | -        array('%error' => $error));
 | 
	
		
			
				|  |  | +        'Tripal Remote web services document reports the following error: !error. Using URL: !url',
 | 
	
		
			
				|  |  | +      array('!error' => $error, '!url' => $ws_url));
 | 
	
		
			
				|  |  |      return FALSE;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  return $data;
 | 
	
		
			
				|  |  | +  cache_set($cache_name, $site_doc);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return $site_doc;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * Build and return a "fake" entity for a record from a remote Tripal site.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @param $remote_entity_id
 | 
	
		
			
				|  |  | + *   Array of the remote ids.
 | 
	
		
			
				|  |  | + * @param $site_id
 | 
	
		
			
				|  |  | + *   The numeric site ID for the remote Tripal site.
 | 
	
		
			
				|  |  | + * @param $bundle_accession
 | 
	
		
			
				|  |  | + *   The controlled vocabulary term accession for the content type
 | 
	
		
			
				|  |  | + *   on the remote Tripal site.
 | 
	
		
			
				|  |  | + * @param $field_ids
 | 
	
		
			
				|  |  | + *   The controlled vocabulary term accessions for the fields available
 | 
	
		
			
				|  |  | + *   on the remote content type.  Any remote fields that matches these IDs will
 | 
	
		
			
				|  |  | + *   be added to the entity returned.
 | 
	
		
			
				|  |  | + * @return
 | 
	
		
			
				|  |  | + *    A fake entity object.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +function tripal_load_remote_entity($remote_entity_id, $site_id, $bundle_accession, $field_ids) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Get the site documentation (loads from cache if already retrieved).
 | 
	
		
			
				|  |  | +  $site_doc = tripal_get_remote_API_doc($site_id);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Get the remote entity and create the fake entity.
 | 
	
		
			
				|  |  | +  $query = $bundle_accession . '/' . $remote_entity_id;
 | 
	
		
			
				|  |  | +  $remote_entity = tripal_query_remote_site($site_id, $query);
 | 
	
		
			
				|  |  | +  if (!$remote_entity) {
 | 
	
		
			
				|  |  | +    return FALSE;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Start building the fake id.
 | 
	
		
			
				|  |  | +  $entity = new stdClass();
 | 
	
		
			
				|  |  | +  $entity->entityType = 'TripalEntity';
 | 
	
		
			
				|  |  | +  $entity->entityInfo = [];
 | 
	
		
			
				|  |  | +  $entity->id = $remote_entity_id;
 | 
	
		
			
				|  |  | +  $entity->type = 'TripalEntity';
 | 
	
		
			
				|  |  | +  $entity->bundle = $bundle_accession;
 | 
	
		
			
				|  |  | +  $entity->site_id = $site_id;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Get the context JSON for this remote entity, we'll use it to map
 | 
	
		
			
				|  |  | +  $context_url = $remote_entity['@context'];
 | 
	
		
			
				|  |  | +  $context = tripal_get_remote_content_context($site_id, $context_url, $bundle_accession);
 | 
	
		
			
				|  |  | +  if (!$context) {
 | 
	
		
			
				|  |  | +    return $entity;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Iterate through the fields and the those values to the entity.
 | 
	
		
			
				|  |  | +  foreach ($field_ids as $field_id) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    $field = tripal_get_remote_field_info($site_id, $bundle_accession, $field_id);
 | 
	
		
			
				|  |  | +    $instance = tripal_get_remote_field_instance_info($site_id, $bundle_accession, $field_id);
 | 
	
		
			
				|  |  | +    $field_name = $field['field_name'];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    $field_key = '';
 | 
	
		
			
				|  |  | +    foreach ($context as $k => $v) {
 | 
	
		
			
				|  |  | +      if (!is_array($v) and $v == $field_id) {
 | 
	
		
			
				|  |  | +        $field_key = $k;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // If the field is not in this remote bundle then add an empty value.
 | 
	
		
			
				|  |  | +    if (!$field_key) {
 | 
	
		
			
				|  |  | +      $entity->{$field_name}['und'][0]['value'] = '';
 | 
	
		
			
				|  |  | +      continue;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if (!array_key_exists($field_key, $remote_entity)) {
 | 
	
		
			
				|  |  | +      $entity->{$field_name}['und'][0]['value'] = '';
 | 
	
		
			
				|  |  | +      continue;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // If the key is for a field that is not "auto attached' then we need
 | 
	
		
			
				|  |  | +    // to get that field through a separate call.
 | 
	
		
			
				|  |  | +    $attached = TRUE;
 | 
	
		
			
				|  |  | +    if (array_key_exists($field_id, $context) and is_array($context[$field_id]) and
 | 
	
		
			
				|  |  | +        array_key_exists('@type', $context[$field_id]) and $context[$field_id]['@type'] == '@id'){
 | 
	
		
			
				|  |  | +          $attached = FALSE;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Set the value for this field.
 | 
	
		
			
				|  |  | +    $value = '';
 | 
	
		
			
				|  |  | +    if (is_array($remote_entity[$field_key])) {
 | 
	
		
			
				|  |  | +      $value = _tripal_update_remote_entity_field($remote_entity[$field_key], $context, 1);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    else {
 | 
	
		
			
				|  |  | +      $value = $remote_entity[$field_key];
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // If the field is not attached then we have to query another level.
 | 
	
		
			
				|  |  | +    if (!$attached) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      $field_data = drupal_http_request($value);
 | 
	
		
			
				|  |  | +      if (!$field_data) {
 | 
	
		
			
				|  |  | +        tripal_report_error('tripal_ws', TRIPAL_ERROR,
 | 
	
		
			
				|  |  | +           'There was a poblem retrieving the unattached field, "!field:", for the remote entity: !entity_id.',
 | 
	
		
			
				|  |  | +            array('!field' => $field_id, '!entity_id' => $remote_entity_id));
 | 
	
		
			
				|  |  | +        $value = '';
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      $field_data = drupal_json_decode($field_data->data);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // Get the context for this field so we can map the keys to the
 | 
	
		
			
				|  |  | +      // controlled vocabulary accessions. If it fails then skip this field.
 | 
	
		
			
				|  |  | +      $field_context_url = $field_data['@context'];
 | 
	
		
			
				|  |  | +      $field_context = tripal_get_remote_content_context($site_id, $field_context_url, $bundle_accession, $field_id);
 | 
	
		
			
				|  |  | +      if (!$field_context) {
 | 
	
		
			
				|  |  | +        continue;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      $value = _tripal_update_remote_entity_field($field_data, $field_context);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    $entity->{$field_name}['und'][0]['value'] = $value;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  return $entity;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * A helper function for the tripal_get_remote_entity() function.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * This function converts the field's key elements to their
 | 
	
		
			
				|  |  | + * vocabulary term accessions.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @param $field_data
 | 
	
		
			
				|  |  | + *   The field array as returned by web services.
 | 
	
		
			
				|  |  | + * @param $context
 | 
	
		
			
				|  |  | + *   The web service JSON-LD context for the bundle to which the field belongs.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +function _tripal_update_remote_entity_field($field_data, $context, $depth = 0) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // If depth is 0 then we are tring to find out how to deal with this field.
 | 
	
		
			
				|  |  | +  if ($depth == 0) {
 | 
	
		
			
				|  |  | +    // Check if this is an array.
 | 
	
		
			
				|  |  | +    if ($field_data['@type'] == 'Collection') {
 | 
	
		
			
				|  |  | +      $members = array();
 | 
	
		
			
				|  |  | +      foreach ($field_data['member'] as $member) {
 | 
	
		
			
				|  |  | +        $next_depth = $depth + 1;
 | 
	
		
			
				|  |  | +        $members[] = _tripal_update_remote_entity_field($member, $context, $next_depth);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // If we only have one item then just return it as a single item.
 | 
	
		
			
				|  |  | +      // TODO: we may need to check cardinality of the field and be more
 | 
	
		
			
				|  |  | +      // strict about how we return the value.
 | 
	
		
			
				|  |  | +      if ($field_data['totalItems'] == 1){
 | 
	
		
			
				|  |  | +        return $members[0];
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      else {
 | 
	
		
			
				|  |  | +        return $members;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    else {
 | 
	
		
			
				|  |  | +      $next_depth = $depth + 1;
 | 
	
		
			
				|  |  | +      return _tripal_update_remote_entity_field($field_data, $context, $next_depth);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  // If this isn't depth 0 then we are rewriting keys as CV term accession.
 | 
	
		
			
				|  |  | +  else {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    $value = array();
 | 
	
		
			
				|  |  | +    foreach ($field_data as $k => $v) {
 | 
	
		
			
				|  |  | +      // Skip the JSON-LD keys.
 | 
	
		
			
				|  |  | +      if ($k == '@id' or $k == '@type' or $k == '@context') {
 | 
	
		
			
				|  |  | +        continue;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      // Find the term accession for this element, and if the key's value is an
 | 
	
		
			
				|  |  | +      // array then recurse.
 | 
	
		
			
				|  |  | +      $accession = $context[$k];
 | 
	
		
			
				|  |  | +      if (is_array($v)) {
 | 
	
		
			
				|  |  | +        $next_depth = $depth + 1;
 | 
	
		
			
				|  |  | +        $subvalue = _tripal_update_remote_entity_field($v, $context, $next_depth);
 | 
	
		
			
				|  |  | +        $value[$accession] = $value;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      else {
 | 
	
		
			
				|  |  | +        $value[$accession] = $v;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return $value;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * Behaves similar to the field_info_field() function but for remote fields.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Returns a "fake" field info array for fields attached to content types
 | 
	
		
			
				|  |  | + * on remote Tripal sites.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @param $site_id
 | 
	
		
			
				|  |  | + *   The numeric site ID for the remote Tripal site.
 | 
	
		
			
				|  |  | + * @param $bundle_accession
 | 
	
		
			
				|  |  | + *   The controlled vocabulary term accession for the content type
 | 
	
		
			
				|  |  | + *   on the remote Tripal site.
 | 
	
		
			
				|  |  | + * @param $field_accession
 | 
	
		
			
				|  |  | + *   The controlled vocabulary term accession for the property (i.e. field) of
 | 
	
		
			
				|  |  | + *   the Class (i.e. content type).
 | 
	
		
			
				|  |  | + * @return
 | 
	
		
			
				|  |  | + *   An array similar to that returned by the field_info_field function
 | 
	
		
			
				|  |  | + *   of Drupal for local fields.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +function tripal_get_remote_field_info($site_id, $bundle_accession, $field_accession){
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Get the site documentation (loads from cache if already retrieved).
 | 
	
		
			
				|  |  | +  $site_doc = tripal_get_remote_API_doc($site_id);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Get the property from the document for this field.
 | 
	
		
			
				|  |  | +  $property = tripal_get_remote_field_doc($site_id, $bundle_accession, $field_accession);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Now create the fake field and instance.
 | 
	
		
			
				|  |  | +  list($vocab, $accession) = explode(':', $field_accession);
 | 
	
		
			
				|  |  | +  $field_name = 'tripal_remote_site_' . $site_id . '_' . $field_accession;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  $field = array(
 | 
	
		
			
				|  |  | +    'field_name' => $field_name,
 | 
	
		
			
				|  |  | +    'type' => $field_name,
 | 
	
		
			
				|  |  | +    'storage' => array(
 | 
	
		
			
				|  |  | +      'type' => 'tripal_remote_site'
 | 
	
		
			
				|  |  | +    ),
 | 
	
		
			
				|  |  | +  );
 | 
	
		
			
				|  |  | +  return $field;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * Behaves similar to the field_info_instance() function but for remote fields.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Returns a "fake" instance info array for fields attached to content types
 | 
	
		
			
				|  |  | + * on remote Tripal sites.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @param $site_id
 | 
	
		
			
				|  |  | + *   The numeric site ID for the remote Tripal site.
 | 
	
		
			
				|  |  | + * @param $bundle_accession
 | 
	
		
			
				|  |  | + *   The controlled vocabulary term accession for the content type
 | 
	
		
			
				|  |  | + *   on the remote Tripal site.
 | 
	
		
			
				|  |  | + * @param $field_accession
 | 
	
		
			
				|  |  | + *   The controlled vocabulary term accession for the property (i.e. field) of
 | 
	
		
			
				|  |  | + *   the Class (i.e. content type).
 | 
	
		
			
				|  |  | + * @return
 | 
	
		
			
				|  |  | + *   An array similar to that returned by the field_info_instance function
 | 
	
		
			
				|  |  | + *   of Drupal for local fields.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +function tripal_get_remote_field_instance_info($site_id, $bundle_accession, $field_accession){
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Get the site documentation (loads from cache if already retrieved).
 | 
	
		
			
				|  |  | +  $site_doc = tripal_get_remote_API_doc($site_id);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Get the property from the document for this field.
 | 
	
		
			
				|  |  | +  $property = tripal_get_remote_field_doc($site_id, $bundle_accession, $field_accession);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  list($vocab, $accession) = explode(':', $field_accession);
 | 
	
		
			
				|  |  | +  $field_name = 'tripal_remote_site_' . $site_id . '_' . $field_accession;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  list($vocab, $accession) = explode(':', $field_accession);
 | 
	
		
			
				|  |  | +  $instance = array(
 | 
	
		
			
				|  |  | +    'label' => $property['hydra:title'],
 | 
	
		
			
				|  |  | +    'description' => $property['hydra:description'],
 | 
	
		
			
				|  |  | +    'formatters' => $property['tripal_formatters'],
 | 
	
		
			
				|  |  | +    'settings' => array(
 | 
	
		
			
				|  |  | +      'term_vocabulary' => $vocab,
 | 
	
		
			
				|  |  | +      'term_accession' => $accession
 | 
	
		
			
				|  |  | +    ),
 | 
	
		
			
				|  |  | +    'field_name' => $field_name,
 | 
	
		
			
				|  |  | +    'entity_type' => 'TripalEntity',
 | 
	
		
			
				|  |  | +    'bundle_name' => $bundle_accession,
 | 
	
		
			
				|  |  | +  );
 | 
	
		
			
				|  |  | +  return $instance;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * Retreive the bundle (content type) information from a remote Tripal site.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * The array returned is equivalent to the Hydra Vocabulary "supportedClass"
 | 
	
		
			
				|  |  | + * stanza.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @param $site_id
 | 
	
		
			
				|  |  | + *   The numeric site ID for the remote Tripal site.
 | 
	
		
			
				|  |  | + * @param $bundle_accession
 | 
	
		
			
				|  |  | + *   The controlled vocabulary term accession for the content type
 | 
	
		
			
				|  |  | + *   on the remote Tripal site.
 | 
	
		
			
				|  |  | + * @return
 | 
	
		
			
				|  |  | + *   A PHP array corresponding to the Hydra Class stanza (i.e. a content type).
 | 
	
		
			
				|  |  | + *   Returns NULL if the class ID cannot be found.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +function tripal_get_remote_bundle_doc($site_id, $bundle_accession){
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Get the site documentation (loads from cache if already retrieved).
 | 
	
		
			
				|  |  | +  $site_doc = tripal_get_remote_API_doc($site_id);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Get the class that matches this bundle.
 | 
	
		
			
				|  |  | +  $classes = $site_doc['supportedClass'];
 | 
	
		
			
				|  |  | +  $class = NULL;
 | 
	
		
			
				|  |  | +  foreach ($classes as $item) {
 | 
	
		
			
				|  |  | +    if ($item['@id'] == $bundle_accession) {
 | 
	
		
			
				|  |  | +      return $item;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  return NULL;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * Retrieves the field information for a content type from a remote Tripal site.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * The array returned is equivalent to the Hydra Vocabulary "supportedProperty"
 | 
	
		
			
				|  |  | + * stanza that belongs to a Hydra Class (content type).
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @param $site_id
 | 
	
		
			
				|  |  | + *   The numeric site ID for the remote Tripal site.
 | 
	
		
			
				|  |  | + * @param $bundle_accession
 | 
	
		
			
				|  |  | + *   The controlled vocabulary term accession for the content type
 | 
	
		
			
				|  |  | + *   on the remote Tripal site.
 | 
	
		
			
				|  |  | + * @param $field_accession
 | 
	
		
			
				|  |  | + *   The controlled vocabulary term accession for the property (i.e. field) of
 | 
	
		
			
				|  |  | + *   the Class (i.e. content type).
 | 
	
		
			
				|  |  | + * @return
 | 
	
		
			
				|  |  | + *   A PHP array corresponding to the Hydra property stanza (field) that
 | 
	
		
			
				|  |  | + *   belongs to the given Class (i.e. a content type).  Retruns NULL if the
 | 
	
		
			
				|  |  | + *   property cannot be found.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +function tripal_get_remote_field_doc($site_id, $bundle_accession, $field_accession){
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Get the site documentation (loads from cache if already retrieved).
 | 
	
		
			
				|  |  | +  $site_doc = tripal_get_remote_API_doc($site_id);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  $class = tripal_get_remote_bundle_doc($site_id, $bundle_accession);
 | 
	
		
			
				|  |  | +  $properties = $class['supportedProperty'];
 | 
	
		
			
				|  |  | +  foreach ($properties as $item) {
 | 
	
		
			
				|  |  | +    if ($item['property'] == $field_accession) {
 | 
	
		
			
				|  |  | +      return $item;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  return NULL;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * Retrieves the list of download formatters for a remote field.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * All Tripal fields support the abilty for inclusion in files that can
 | 
	
		
			
				|  |  | + * downloaded.  This function is used to identify what formatters these
 | 
	
		
			
				|  |  | + * fields are appropriate for. If those download formatter classes exist
 | 
	
		
			
				|  |  | + * on this site then the field can be used with that formatter.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * @param $site_id
 | 
	
		
			
				|  |  | + *   The numeric site ID for the remote Tripal site.
 | 
	
		
			
				|  |  | + * @param $bundle_accession
 | 
	
		
			
				|  |  | + *   The controlled vocabulary term accession for the content type
 | 
	
		
			
				|  |  | + *   on the remote Tripal site.
 | 
	
		
			
				|  |  | + * @param $field_accession
 | 
	
		
			
				|  |  | + *   The controlled vocabulary term accession for the property (i.e. field) of
 | 
	
		
			
				|  |  | + *   the Class (i.e. content type).
 | 
	
		
			
				|  |  | + * @return
 | 
	
		
			
				|  |  | + *   An array of field downloader class names that are compoatible with the
 | 
	
		
			
				|  |  | + *   field and which exist on this site.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +function tripal_get_remote_field_formatters($site_id, $bundle_accession, $field_accession) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  $flist = array();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Get the site documentation (loads from cache if already retrieved).
 | 
	
		
			
				|  |  | +  $site_doc = tripal_get_remote_API_doc($site_id);
 | 
	
		
			
				|  |  | +  $property = tripal_get_remote_field_doc($site_id, $bundle_accession, $field_accession);
 | 
	
		
			
				|  |  | +  if (!$property) {
 | 
	
		
			
				|  |  | +    return $flist;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  $formatters = $property['tripal_formatters'];
 | 
	
		
			
				|  |  | +  foreach($formatters as $formatter) {
 | 
	
		
			
				|  |  | +    if (tripal_load_include_downloader_class($formatter)) {
 | 
	
		
			
				|  |  | +      $flist[$formatter] = $formatter::$full_label;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  return $flist;
 | 
	
		
			
				|  |  |  }
 |