|  | @@ -16,9 +16,9 @@
 | 
	
		
			
				|  |  |   * drupal_eval() which suppresses syntax errors and throws watchdog entries of type php. There are
 | 
	
		
			
				|  |  |   * also watchdog entries of type tripal_core stating the exact criteria evaluated. Criteria can
 | 
	
		
			
				|  |  |   * contain the following tokens:
 | 
	
		
			
				|  |  | - *   - >field_name<
 | 
	
		
			
				|  |  | + *   - <field_name>
 | 
	
		
			
				|  |  |   *       Replaced by the name of the field to be excluded
 | 
	
		
			
				|  |  | - *   - >field_value<
 | 
	
		
			
				|  |  | + *   - <field_value>
 | 
	
		
			
				|  |  |   *       Replaced by the value of the field in the current record
 | 
	
		
			
				|  |  |   * Also keep in mind that if your criteria doesn't contain the >field_value<  token then it will be
 | 
	
		
			
				|  |  |   * evaluated before the query is executed and if the field is excluded it won't be included in the
 | 
	
	
		
			
				|  | @@ -30,7 +30,7 @@
 | 
	
		
			
				|  |  |   * @ingroup tripal_chado_query_api
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  function tripal_core_exclude_type_by_default() {
 | 
	
		
			
				|  |  | -  return array('text' => 'strlen(">field_value< ") > 100');
 | 
	
		
			
				|  |  | +  return array('text' => 'strlen("<field_value> ") > 250');
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
	
		
			
				|  | @@ -45,21 +45,21 @@ function tripal_core_exclude_type_by_default() {
 | 
	
		
			
				|  |  |   * drupal_eval() which suppresses syntax errors and throws watchdog entries of type php. There are
 | 
	
		
			
				|  |  |   * also watchdog entries of type tripal_core stating the exact criteria evaluated. Criteria can
 | 
	
		
			
				|  |  |   * contain the following tokens:
 | 
	
		
			
				|  |  | - *   - >field_name<
 | 
	
		
			
				|  |  | + *   - <field_name>
 | 
	
		
			
				|  |  |   *       Replaced by the name of the field to be excluded
 | 
	
		
			
				|  |  | - *   - >field_value<
 | 
	
		
			
				|  |  | + *   - <field_value>
 | 
	
		
			
				|  |  |   *       Replaced by the value of the field in the current record
 | 
	
		
			
				|  |  | - * Also keep in mind that if your criteria doesn't contain the >field_value<  token then it will be
 | 
	
		
			
				|  |  | + * Also keep in mind that if your criteria doesn't contain the <field_value>  token then it will be
 | 
	
		
			
				|  |  |   * evaluated before the query is executed and if the field is excluded it won't be included in the
 | 
	
		
			
				|  |  |   * query.
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  |   * @return
 | 
	
		
			
				|  |  | - *   An array of type => criteria where the type is excluded if the criteria evaluates to TRUE
 | 
	
		
			
				|  |  | + *   An array of field => criteria where the type is excluded if the criteria evaluates to TRUE
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  |   * @ingroup tripal_chado_query_api
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  function tripal_core_exclude_field_from_feature_by_default() {
 | 
	
		
			
				|  |  | -  return array();
 | 
	
		
			
				|  |  | +  return array('residues' => 'TRUE');
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
	
		
			
				|  | @@ -161,7 +161,7 @@ function chado_generate_var($table, $values, $base_options = array()) {
 | 
	
		
			
				|  |  |    if (array_key_exists('return_array', $base_options)) {
 | 
	
		
			
				|  |  |      $return_array = 1;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  $include_fk = 0;
 | 
	
		
			
				|  |  | +  $include_fk = FALSE;
 | 
	
		
			
				|  |  |    if (array_key_exists('include_fk', $base_options)) {
 | 
	
		
			
				|  |  |      $include_fk = $base_options['include_fk'];
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -185,7 +185,10 @@ function chado_generate_var($table, $values, $base_options = array()) {
 | 
	
		
			
				|  |  |    $table_columns = array_keys($table_desc['fields']);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Expandable fields without value needed for criteria--------------------------------------------
 | 
	
		
			
				|  |  | +  // Add in the default expandable arrays
 | 
	
		
			
				|  |  | +  // These are used for later expanding fields, tables, foreign keys and nodes
 | 
	
		
			
				|  |  |    $all->expandable_fields = array();
 | 
	
		
			
				|  |  | +  $all->expandable_foreign_keys = array();
 | 
	
		
			
				|  |  |    if (array_key_exists('referring_tables', $table_desc) and $table_desc['referring_tables']) {
 | 
	
		
			
				|  |  |      $all->expandable_tables = $table_desc['referring_tables'];
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -194,19 +197,40 @@ function chado_generate_var($table, $values, $base_options = array()) {
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    $all->expandable_nodes = array();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /*
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    // Get fields to be removed by name.................................
 | 
	
		
			
				|  |  | +  // This gets all implementations of hook_exclude_field_from_<table>_by_default()
 | 
	
		
			
				|  |  | +  // where <table> is the current table a variable is being created for.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // This allows modules to specify that some fields should be excluded by default
 | 
	
		
			
				|  |  | +  // For example, tripal core provides a tripal_core_exclude_field_from_feature_by_default()
 | 
	
		
			
				|  |  | +  // which says that we usually don't want to include the residues field by default since
 | 
	
		
			
				|  |  | +  // it can be very large and cause performance issues.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // If a field is excluded by default it can always be expanded at a later point by calling
 | 
	
		
			
				|  |  | +  // chado_expand_var($chado_var, 'field', <field name as shown in expandable_fields array>);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // First get an array of all the fields to be removed for the current table
 | 
	
		
			
				|  |  | +  // module_invoke_all() is drupal's way of invoking all implementations of the specified
 | 
	
		
			
				|  |  | +  // hook and merging all of the results.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // $fields_to_remove should be an array with the keys matching field names
 | 
	
		
			
				|  |  | +  // and the values being strings to be executed using php_eval() to determine whether
 | 
	
		
			
				|  |  | +  // to exclude the field (evaluates to TRUE) or not (evaluates to FALSE)
 | 
	
		
			
				|  |  |    $fields_to_remove = module_invoke_all('exclude_field_from_' . $table . '_by_default');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Now, for each field to be removed
 | 
	
		
			
				|  |  |    foreach ($fields_to_remove as $field_name => $criteria) {
 | 
	
		
			
				|  |  | -    //replace >field_name<  with the current field name &
 | 
	
		
			
				|  |  | -    $criteria = preg_replace('/>field_name< /', addslashes($field_name), $criteria);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    //replace <field_name> with the current field name
 | 
	
		
			
				|  |  | +    $criteria = preg_replace('/<field_name> /', addslashes($field_name), $criteria);
 | 
	
		
			
				|  |  |      // if field_value needed we can't deal with this field yet
 | 
	
		
			
				|  |  | -    if (preg_match('/>field_value< /', $criteria)) {
 | 
	
		
			
				|  |  | +    if (preg_match('/<field_value> /', $criteria)) {
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      //if criteria then remove from query
 | 
	
		
			
				|  |  | -    // @coder-ignore: only module designers can populate $criteria -not security risk
 | 
	
		
			
				|  |  | +    // @coder-ignore: only module designers can populate $criteria -not a security risk
 | 
	
		
			
				|  |  |      $success = php_eval('<?php return ' . $criteria . '; ?>');
 | 
	
		
			
				|  |  |      if ($success) {
 | 
	
		
			
				|  |  |        unset($table_columns[array_search($field_name, $table_columns)]);
 | 
	
	
		
			
				|  | @@ -215,29 +239,54 @@ function chado_generate_var($table, $values, $base_options = array()) {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  //Get fields to be removed by type................................
 | 
	
		
			
				|  |  | +  // Get fields to be removed by type................................
 | 
	
		
			
				|  |  | +  // This gets all implementations of hook_exclude_type_by_default().
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // This allows modules to specify that some types of fields should be excluded by default
 | 
	
		
			
				|  |  | +  // For example, tripal core provides a tripal_core_exclude_type_by_default() which says
 | 
	
		
			
				|  |  | +  // that text fields are often very large and if they are longer than 250 characters then
 | 
	
		
			
				|  |  | +  // we want to exclude them by default
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // If a field is excluded by default it can always be expanded at a later point by calling
 | 
	
		
			
				|  |  | +  // chado_expand_var($chado_var, 'field', <field name as shown in expandable_fields array>);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // First get an array of all the types of fields to be removed for the current table
 | 
	
		
			
				|  |  | +  // module_invoke_all() is drupal's way of invoking all implementations of the specified
 | 
	
		
			
				|  |  | +  // hook and merging all of the results.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // $types_to_remove should be an array with the keys matching field names
 | 
	
		
			
				|  |  | +  // and the values being strings to be executed using php_eval() to determine whether
 | 
	
		
			
				|  |  | +  // to exclude the field (evaluates to TRUE) or not (evaluates to FALSE)
 | 
	
		
			
				|  |  | +  // (ie: array('text' => 'strlen("<field_value> ") > 100');
 | 
	
		
			
				|  |  |    $types_to_remove = module_invoke_all('exclude_type_by_default');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Get a list of all the types of fields
 | 
	
		
			
				|  |  | +  // the key is the type of field and the value is an array of fields of this type
 | 
	
		
			
				|  |  |    $field_types = array();
 | 
	
		
			
				|  |  |    foreach ($table_desc['fields'] as $field_name => $field_array) {
 | 
	
		
			
				|  |  |      $field_types[$field_array['type']][] = $field_name;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // We want to use the types to remove in conjunction with our table field descriptions
 | 
	
		
			
				|  |  | +  // to determine which fields might need to be removed
 | 
	
		
			
				|  |  |    foreach ($types_to_remove as $field_type => $criteria) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      // if there are fields of that type to remove
 | 
	
		
			
				|  |  | -    if (is_array($field_types[$field_type])) {
 | 
	
		
			
				|  |  | -      //replace >field_name<  with the current field name &
 | 
	
		
			
				|  |  | -      $criteria = preg_replace('/>field_name< /', addslashes($field_name), $criteria);
 | 
	
		
			
				|  |  | +    if (isset($field_types[$field_type])) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // Do any processing needed on the php criteria
 | 
	
		
			
				|  |  | +      //replace <field_name>  with the current field name
 | 
	
		
			
				|  |  | +      $criteria = preg_replace('/<field_name> /', addslashes($field_name), $criteria);
 | 
	
		
			
				|  |  |        foreach ($field_types[$field_type] as $field_name) {
 | 
	
		
			
				|  |  |          // if field_value needed we can't deal with this field yet
 | 
	
		
			
				|  |  | -        if (preg_match('/>field_value< /', $criteria)) {
 | 
	
		
			
				|  |  | +        if (preg_match('/<field_value>/', $criteria)) {
 | 
	
		
			
				|  |  |            $fields_to_remove[$field_name] = $criteria;
 | 
	
		
			
				|  |  |            continue;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        // if field_value needed we can't deal with this field yet
 | 
	
		
			
				|  |  | -        if (preg_match('/>field_value< /', $criteria)) {
 | 
	
		
			
				|  |  | -          break;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        //if criteria then remove from query
 | 
	
		
			
				|  |  | -        // @coder-ignore: only module designers can populate $criteria -not security risk
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // if criteria then remove from query
 | 
	
		
			
				|  |  | +        // (as long as <field_value> is not needed for the criteria to be evaluated)
 | 
	
		
			
				|  |  | +        // @coder-ignore: only module designers can populate $criteria -not a security risk
 | 
	
		
			
				|  |  |          $success = php_eval('<?php return ' . $criteria . '; ?>');
 | 
	
		
			
				|  |  |          if ($success) {
 | 
	
		
			
				|  |  |            unset($table_columns[array_search($field_name, $table_columns)]);
 | 
	
	
		
			
				|  | @@ -246,7 +295,7 @@ function chado_generate_var($table, $values, $base_options = array()) {
 | 
	
		
			
				|  |  |        } //end of foreach field of that type
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    } //end of foreach type to be removed
 | 
	
		
			
				|  |  | -*/
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    // get the values for the record in the current table---------------------------------------------
 | 
	
		
			
				|  |  |    $results = chado_select_record($table, $table_columns, $values, $base_options);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -254,6 +303,7 @@ function chado_generate_var($table, $values, $base_options = array()) {
 | 
	
		
			
				|  |  |      foreach ($results as $key => $object) {
 | 
	
		
			
				|  |  |        // Add empty expandable_x arrays
 | 
	
		
			
				|  |  |        $object->expandable_fields = $all->expandable_fields;
 | 
	
		
			
				|  |  | +      $object->expandable_foreign_keys = $all->expandable_foreign_keys;
 | 
	
		
			
				|  |  |        $object->expandable_tables = $all->expandable_tables;
 | 
	
		
			
				|  |  |        $object->expandable_nodes = $all->expandable_nodes;
 | 
	
		
			
				|  |  |        // add curent table
 | 
	
	
		
			
				|  | @@ -277,23 +327,39 @@ function chado_generate_var($table, $values, $base_options = array()) {
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        // remove any fields where criteria needs to be evalulated---------------------------------------
 | 
	
		
			
				|  |  | -/*      foreach ($fields_to_remove as $field_name => $criteria) {
 | 
	
		
			
				|  |  | +      // The fields to be removed can be populated by implementing either
 | 
	
		
			
				|  |  | +      // hook_exclude_field_from_<table>_by_default() where <table> is the current table
 | 
	
		
			
				|  |  | +      // OR hook_exclude_type_by_default() where there are fields of the specified type in the current table
 | 
	
		
			
				|  |  | +      // It only reaches this point if the criteria specified for whether or not to
 | 
	
		
			
				|  |  | +      // exclude the field includes <field_value> which means it has to be evaluated after
 | 
	
		
			
				|  |  | +      // the query has been executed
 | 
	
		
			
				|  |  | +      foreach ($fields_to_remove as $field_name => $criteria) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // If the field is an object then we don't support exclusion of it
 | 
	
		
			
				|  |  | +        // For example, if the field is a foreign key
 | 
	
		
			
				|  |  |          if (!isset($object->{$field_name})) {
 | 
	
		
			
				|  |  |            break;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        $criteria = preg_replace('/>field_value< /', addslashes($object->{$field_name}), $criteria);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // replace <field_value> with the actual value of the field from the query
 | 
	
		
			
				|  |  | +        $criteria = preg_replace('/<field_value>/', addslashes($object->{$field_name}), $criteria);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // evaluate the criteria, if TRUE is returned then exclude the field
 | 
	
		
			
				|  |  | +        // excluded fields can be expanded later by calling
 | 
	
		
			
				|  |  | +        // chado_expand_var($var, 'field', <field name as shown in expandable_fields array>);
 | 
	
		
			
				|  |  |          $success = php_eval('<?php return ' . $criteria . '; ?>');
 | 
	
		
			
				|  |  |          if ($success) {
 | 
	
		
			
				|  |  |            unset($object->{$field_name});
 | 
	
		
			
				|  |  |            $object->expandable_fields[] = $table . '.' . $field_name;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | -*/
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |        // recursively follow foreign key relationships nesting objects as we go------------------------
 | 
	
		
			
				|  |  |        if ($table_desc['foreign keys']) {
 | 
	
		
			
				|  |  |          foreach ($table_desc['foreign keys'] as $foreign_key_array) {
 | 
	
		
			
				|  |  |            $foreign_table = $foreign_key_array['table'];
 | 
	
		
			
				|  |  |            foreach ($foreign_key_array['columns'] as $foreign_key => $primary_key) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |              // Note: Foreign key is the field in the current table whereas primary_key is the field in
 | 
	
		
			
				|  |  |              // the table referenced by the foreign key
 | 
	
		
			
				|  |  |              //Dont do anything if the foreign key is empty
 | 
	
	
		
			
				|  | @@ -301,17 +367,20 @@ function chado_generate_var($table, $values, $base_options = array()) {
 | 
	
		
			
				|  |  |                continue;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            if ($include_fk) {
 | 
	
		
			
				|  |  | +            if (is_array($include_fk)) {
 | 
	
		
			
				|  |  |                // don't recurse if the callee has supplied an $fk_include list and this
 | 
	
		
			
				|  |  |                // FK table is not in the list.
 | 
	
		
			
				|  |  |                if (is_array($include_fk) and !array_key_exists($foreign_key, $include_fk)) {
 | 
	
		
			
				|  |  | -                continue;
 | 
	
		
			
				|  |  | -              }
 | 
	
		
			
				|  |  | -              // if we have the option but it is not an array then we don't recurse any furutehr
 | 
	
		
			
				|  |  | -              if (!is_array($include_fk)) {
 | 
	
		
			
				|  |  | +                $object->expandable_foreign_keys[] = $table . '.' . $foreign_key . ' => ' . $foreign_table;
 | 
	
		
			
				|  |  |                  continue;
 | 
	
		
			
				|  |  |                }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | +            // if we have the option but it is not an array then we don't recurse any furutehr
 | 
	
		
			
				|  |  | +            if ($include_fk === TRUE) {
 | 
	
		
			
				|  |  | +              $object->expandable_foreign_keys[] = $table . '.' . $foreign_key . ' => ' . $foreign_table;
 | 
	
		
			
				|  |  | +              continue;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |              // get the record from the foreign table
 | 
	
		
			
				|  |  |              $foreign_values = array($primary_key => $object->{$foreign_key});
 | 
	
		
			
				|  |  |              $options = array();
 | 
	
	
		
			
				|  | @@ -332,6 +401,14 @@ function chado_generate_var($table, $values, $base_options = array()) {
 | 
	
		
			
				|  |  |                );
 | 
	
		
			
				|  |  |                unset($object->{$foreign_key}->expandable_fields);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | +            if (property_exists($object->{$foreign_key}, 'expandable_foreign_keys') and
 | 
	
		
			
				|  |  | +                is_array($object->{$foreign_key}->expandable_foreign_keys)) {
 | 
	
		
			
				|  |  | +              $object->expandable_foreign_keys = array_merge(
 | 
	
		
			
				|  |  | +                $object->expandable_foreign_keys,
 | 
	
		
			
				|  |  | +                $object->{$foreign_key}->expandable_foreign_keys
 | 
	
		
			
				|  |  | +              );
 | 
	
		
			
				|  |  | +              unset($object->{$foreign_key}->expandable_foreign_keys);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |              if (property_exists($object->{$foreign_key}, 'expandable_tables') and
 | 
	
		
			
				|  |  |                  is_array($object->{$foreign_key}->expandable_tables)) {
 | 
	
		
			
				|  |  |                $object->expandable_tables = array_merge(
 | 
	
	
		
			
				|  | @@ -484,20 +561,33 @@ function chado_expand_var($object, $type, $to_expand, $table_options = array())
 | 
	
		
			
				|  |  |          $tablename = $matches[1];
 | 
	
		
			
				|  |  |          $fieldname = $matches[2];
 | 
	
		
			
				|  |  |          $table_desc = chado_get_schema($tablename);
 | 
	
		
			
				|  |  | -        $values = array();
 | 
	
		
			
				|  |  | -        foreach ($table_desc['primary key'] as $key) {
 | 
	
		
			
				|  |  | -          if(property_exists($object, $key)) {
 | 
	
		
			
				|  |  | -            $values[$key] = $object->{$key};
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // BASE CASE: the field is from the current table
 | 
	
		
			
				|  |  |          if ($base_table == $tablename) {
 | 
	
		
			
				|  |  | -          //get the field
 | 
	
		
			
				|  |  | +          // Use the table description to fully describe the current object
 | 
	
		
			
				|  |  | +          // in a $values array to be used to select the field from chado
 | 
	
		
			
				|  |  | +          $values = array();
 | 
	
		
			
				|  |  | +          foreach ($table_desc['primary key'] as $key) {
 | 
	
		
			
				|  |  | +            if(property_exists($object, $key)) {
 | 
	
		
			
				|  |  | +              $values[$key] = $object->{$key};
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // Retrieve the field from Chado
 | 
	
		
			
				|  |  |            $results = chado_select_record($tablename, array($fieldname), $values);
 | 
	
		
			
				|  |  | -          $object->{$fieldname} = $results[0]->{$fieldname};
 | 
	
		
			
				|  |  | -          $object->expanded = $to_expand;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // Check that the field was retrieved correctly
 | 
	
		
			
				|  |  | +          if (isset($results[0])) {
 | 
	
		
			
				|  |  | +            $object->{$fieldname} = $results[0]->{$fieldname};
 | 
	
		
			
				|  |  | +            $object->expanded = $to_expand;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          // If it wasn't retrieved correctly, we need to warn the administrator
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        // RECURSIVE CASE: the field is in a nested object
 | 
	
		
			
				|  |  |          else {
 | 
	
		
			
				|  |  | -          //We need to recurse -the field is in a nested object
 | 
	
		
			
				|  |  | +          // We want to look at each field and if it's an object then we want to
 | 
	
		
			
				|  |  | +          // attempt to expand the field in it via recursion
 | 
	
		
			
				|  |  |            foreach ((array) $object as $field_name => $field_value) {
 | 
	
		
			
				|  |  |              if (is_object($field_value)) {
 | 
	
		
			
				|  |  |                $object->{$field_name} = chado_expand_var(
 | 
	
	
		
			
				|  | @@ -509,22 +599,110 @@ function chado_expand_var($object, $type, $to_expand, $table_options = array())
 | 
	
		
			
				|  |  |            } //end of for each field in the current object
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | +      // Otherwise we weren't able to extract the parts of the field to expand
 | 
	
		
			
				|  |  | +      // Thus we will warn the administrator
 | 
	
		
			
				|  |  |        else {
 | 
	
		
			
				|  |  |          tripal_report_error('tripal_core', TRIPAL_ERROR,
 | 
	
		
			
				|  |  |            'chado_expand_var: Field (%field) not in the right format. " .
 | 
	
		
			
				|  |  | -          "It should be <tablename>.<fieldname>');
 | 
	
		
			
				|  |  | +          "It should be <tablename>.<fieldname>', array('%field' => $to_expand));
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    case "foreign_key": //--------------------------------------------------------------------------
 | 
	
		
			
				|  |  | +      if (preg_match('/(\w+)\.(\w+) => (\w+)/', $to_expand, $matches)) {
 | 
	
		
			
				|  |  | +        $table_name = $matches[1];
 | 
	
		
			
				|  |  | +        $field_name = $matches[2];
 | 
	
		
			
				|  |  | +        $foreign_table = $matches[3];
 | 
	
		
			
				|  |  | +        $table_desc = chado_get_schema($table_name);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // BASE CASE: The foreign key is from the current table
 | 
	
		
			
				|  |  | +        if ($base_table == $table_name) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // Get the value of the foreign key from the object
 | 
	
		
			
				|  |  | +          $field_value = $object->{$field_name};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // Get the name of the field in the foreign table using the table description
 | 
	
		
			
				|  |  | +          // For example, with the feature.type_id => cvterm.cvterm_id we need cvterm_id
 | 
	
		
			
				|  |  | +          $foreign_field_name = FALSE;
 | 
	
		
			
				|  |  | +          foreach ($table_desc['foreign keys'][$foreign_table]['columns'] as $left => $right) {
 | 
	
		
			
				|  |  | +            if ($right == $field_name) {
 | 
	
		
			
				|  |  | +              $foreign_field_name = $left;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // Check that we were able to determine the field name in the foreign table
 | 
	
		
			
				|  |  | +          if ($foreign_field_name) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Generate a chado variable of the foreign key
 | 
	
		
			
				|  |  | +            // For example, if the foreign key to expand is feature.type_id
 | 
	
		
			
				|  |  | +            // then we want to generate a chado cvterm variable that matches the feature.type_id
 | 
	
		
			
				|  |  | +            $foreign_var = chado_generate_var(
 | 
	
		
			
				|  |  | +              $foreign_table, // thus in the example above, generate a cvterm var
 | 
	
		
			
				|  |  | +              array($foreign_field_name => $field_value), // where the cvterm.cvterm_id = feature.type_id value
 | 
	
		
			
				|  |  | +              $table_options //pass in the same options given to this function
 | 
	
		
			
				|  |  | +            );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Check that the foreign object was returned
 | 
	
		
			
				|  |  | +            if ($foreign_var) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +              // It was so now we can add this chado variable to our current object
 | 
	
		
			
				|  |  | +              // in place of the key value
 | 
	
		
			
				|  |  | +              $object->{$field_name} = $foreign_var;
 | 
	
		
			
				|  |  | +              $object->expanded = $to_expand;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            // Otherwise we weren't able to expand the foreign key
 | 
	
		
			
				|  |  | +            else {
 | 
	
		
			
				|  |  | +              tripal_report_error('tripal_core', TRIPAL_ERROR,
 | 
	
		
			
				|  |  | +                'chado_expand_var: unable to retrieve the object desribed by the foreign key
 | 
	
		
			
				|  |  | +                while trying to expand %fk.',
 | 
	
		
			
				|  |  | +                array('%fk' => $to_expand));
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          // Else we were unable to determine the field name in the foreign table
 | 
	
		
			
				|  |  | +          else {
 | 
	
		
			
				|  |  | +            tripal_report_error('tripal_core', TRIPAL_ERROR,
 | 
	
		
			
				|  |  | +              'chado_expand_var: unable to determine the field name in the table the foreign
 | 
	
		
			
				|  |  | +              key points to while trying to expand %fk.',
 | 
	
		
			
				|  |  | +              array('%fk' => $to_expand));
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        // RECURSIVE CASE: Check any nested objects
 | 
	
		
			
				|  |  | +        else {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          foreach ((array) $object as $field_name => $field_value) {
 | 
	
		
			
				|  |  | +            if (is_object($field_value)) {
 | 
	
		
			
				|  |  | +              $object->{$field_name} = chado_expand_var(
 | 
	
		
			
				|  |  | +              $field_value,
 | 
	
		
			
				|  |  | +              'foreign_key',
 | 
	
		
			
				|  |  | +              $to_expand
 | 
	
		
			
				|  |  | +              );
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          } //end of for each field in the current object
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      // Otherwise we weren't able to extract the parts of the foreign key to expand
 | 
	
		
			
				|  |  | +      // Thus we will warn the administrator
 | 
	
		
			
				|  |  | +      else {
 | 
	
		
			
				|  |  | +        tripal_report_error('tripal_core', TRIPAL_ERROR,
 | 
	
		
			
				|  |  | +          'chado_expand_var: foreign_key (%fk) not in the right format. " .
 | 
	
		
			
				|  |  | +          "It should be <tablename>.<fieldname>', array('%fk' => $to_expand));
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      case "table": //--------------------------------------------------------------------------------
 | 
	
		
			
				|  |  |        $foreign_table = $to_expand;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      // don't expand the table it already is expanded
 | 
	
		
			
				|  |  | +      // RECURSIVE BASE CASE: don't expand the table it already is expanded
 | 
	
		
			
				|  |  |        if (array_key_exists($foreign_table, $object)) {
 | 
	
		
			
				|  |  |          return $object;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        $foreign_table_desc = chado_get_schema($foreign_table);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      // If it's connected to the base table via a FK constraint
 | 
	
		
			
				|  |  | +      // BASE CASE: If it's connected to the base table via a FK constraint
 | 
	
		
			
				|  |  | +      // then we have all the information needed to expand it now
 | 
	
		
			
				|  |  |        if (array_key_exists($base_table, $foreign_table_desc['foreign keys'])) {
 | 
	
		
			
				|  |  |          foreach ($foreign_table_desc['foreign keys'][$base_table]['columns'] as $left => $right) {
 | 
	
		
			
				|  |  |            // if the FK value in the base table is not there then we can't expand it, so just skip it.
 | 
	
	
		
			
				|  | @@ -574,11 +752,16 @@ function chado_expand_var($object, $type, $to_expand, $table_options = array())
 | 
	
		
			
				|  |  |            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | -      // if the foreign table is not connected to the base table through a FK constraint
 | 
	
		
			
				|  |  | +      // RECURSIVE CASE: if the table is not connected directly to the current base table
 | 
	
		
			
				|  |  | +      // through a foreign key relationship, then maybe it has a relationship to
 | 
	
		
			
				|  |  | +      // one of the nested objects.
 | 
	
		
			
				|  |  |        else {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          // We need to recurse -the table has a relationship to one of the nested objects
 | 
	
		
			
				|  |  | +        // We assume it's a nested object if the value of the field is an object
 | 
	
		
			
				|  |  |          $did_expansion = 0;
 | 
	
		
			
				|  |  |          foreach ((array) $object as $field_name => $field_value) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |            // if we have a nested object ->expand the table in it
 | 
	
		
			
				|  |  |            // check to see if the $field_name is a valid chado table, we don't need
 | 
	
		
			
				|  |  |            // to call chado_expand_var on fields that aren't tables
 | 
	
	
		
			
				|  | @@ -588,6 +771,7 @@ function chado_expand_var($object, $type, $to_expand, $table_options = array())
 | 
	
		
			
				|  |  |              $object->{$field_name} = chado_expand_var($field_value, 'table', $foreign_table);
 | 
	
		
			
				|  |  |            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          // if we did not expand this table we should return a message that the foreign table
 | 
	
		
			
				|  |  |          // could not be expanded
 | 
	
		
			
				|  |  |          if (!$did_expansion) {
 | 
	
	
		
			
				|  | @@ -598,11 +782,19 @@ function chado_expand_var($object, $type, $to_expand, $table_options = array())
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      case "node": //---------------------------------------------------------------------------------
 | 
	
		
			
				|  |  | -      //if the node to be expanded is for our base table, then just expand it
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // BASE CASE: if the node to be expanded is for our base table, then just expand it
 | 
	
		
			
				|  |  |        if ($object->tablename == $to_expand) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Load the node based on the current objects nid (node primary key)
 | 
	
		
			
				|  |  |          $node = node_load($object->nid);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // If we have successfully loaded the node...
 | 
	
		
			
				|  |  |          if ($node) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // Move expandable arrays from the object into the node
 | 
	
		
			
				|  |  |            $object->expanded = $to_expand;
 | 
	
		
			
				|  |  |            $node->expandable_fields = $object->expandable_fields;
 | 
	
		
			
				|  |  |            unset($object->expandable_fields);
 | 
	
	
		
			
				|  | @@ -610,16 +802,29 @@ function chado_expand_var($object, $type, $to_expand, $table_options = array())
 | 
	
		
			
				|  |  |            unset($object->expandable_tables);
 | 
	
		
			
				|  |  |            $node->expandable_nodes = $object->expandable_nodes;
 | 
	
		
			
				|  |  |            unset($object->expandable_nodes);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // The node becomes the base object with the obejct added to it.
 | 
	
		
			
				|  |  | +          // For example, we may start with a feature object with a name, uniquename , type, etc.
 | 
	
		
			
				|  |  | +          // After expanding we will return the node and at $node->feature you will find the original object
 | 
	
		
			
				|  |  |            $node->{$base_table} = $object;
 | 
	
		
			
				|  |  |            $object = $node;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        // Else we were unable to load the node
 | 
	
		
			
				|  |  |          else {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // Warn the administrator
 | 
	
		
			
				|  |  |            tripal_report_error('tripal_core', TRIPAL_ERROR, 'chado_expand_var: No node matches the nid (%nid) supplied.',
 | 
	
		
			
				|  |  |              array('%nid' => $object->nid));
 | 
	
		
			
				|  |  |          } //end of if node
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | +      // RECURSIVE CASE: check to see if the node to be expanded associates with a
 | 
	
		
			
				|  |  | +      // chado table within one of the nested objects.
 | 
	
		
			
				|  |  |        else {
 | 
	
		
			
				|  |  | -        //We need to recurse -the node to expand is one of the nested objects
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // We need to recurse -the node to expand is one of the nested objects
 | 
	
		
			
				|  |  | +        // We assume it's a nested object if the field value is an object
 | 
	
		
			
				|  |  |          foreach ((array) $object as $field_name => $field_value) {
 | 
	
		
			
				|  |  |            if (is_object($field_value)) {
 | 
	
		
			
				|  |  |              $object->{$field_name} = chado_expand_var(
 | 
	
	
		
			
				|  | @@ -631,41 +836,144 @@ function chado_expand_var($object, $type, $to_expand, $table_options = array())
 | 
	
		
			
				|  |  |          } //end of for each field in the current object
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // The $type to be expanded is not yet supported
 | 
	
		
			
				|  |  |      default:
 | 
	
		
			
				|  |  |        tripal_report_error('tripal_core', TRIPAL_ERROR, 'chado_expand_var: Unrecognized type (%type). Should be one of "field", "table", "node".',
 | 
	
		
			
				|  |  |          array('%type' => $type));
 | 
	
		
			
				|  |  |        return FALSE;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  // move extended array downwards
 | 
	
		
			
				|  |  | +  // Move expandable arrays downwards -------------------------------
 | 
	
		
			
				|  |  | +  // If the type was either table or foreign key then a new chado variable was generated
 | 
	
		
			
				|  |  | +  // this variable will have it's own expandable array's which need to be moved down
 | 
	
		
			
				|  |  | +  // and merged with the base objects expandable arrays
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Thus, check all nested objects for expandable arrays
 | 
	
		
			
				|  |  | +  // and if they have them, move them downwards
 | 
	
		
			
				|  |  | +  foreach ( (array)$object as $field_name => $field_value) {
 | 
	
		
			
				|  |  | +    if (is_object($field_value)) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // The current nested object has expandable arrays
 | 
	
		
			
				|  |  | +      if (isset($field_value->expandable_fields)) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Move expandable fields downwards
 | 
	
		
			
				|  |  | +        if (isset($field_value->expandable_fields) and is_array($field_value->expandable_fields)) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // If the current object has it's own expandable fields then merge them
 | 
	
		
			
				|  |  | +          if (isset($object->expandable_fields)) {
 | 
	
		
			
				|  |  | +            $object->expandable_fields = array_merge(
 | 
	
		
			
				|  |  | +              $object->expandable_fields,
 | 
	
		
			
				|  |  | +              $object->{$field_name}->expandable_fields
 | 
	
		
			
				|  |  | +            );
 | 
	
		
			
				|  |  | +            unset($object->{$field_name}->expandable_fields);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          // Otherwise, just move the expandable fields downwards
 | 
	
		
			
				|  |  | +          else {
 | 
	
		
			
				|  |  | +            $object->expandable_fields = $object->{$field_name}->expandable_fields;
 | 
	
		
			
				|  |  | +            unset($object->{$field_name}->expandable_fields);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Move expandable foreign keys downwards
 | 
	
		
			
				|  |  | +        if (isset($field_value->expandable_foreign_keys) and is_array($field_value->expandable_foreign_keys)) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // If the current object has it's own expandable foreign keys then merge them
 | 
	
		
			
				|  |  | +          if (isset($object->expandable_foreign_keys)) {
 | 
	
		
			
				|  |  | +            $object->expandable_foreign_keys = array_merge(
 | 
	
		
			
				|  |  | +              $object->expandable_foreign_keys,
 | 
	
		
			
				|  |  | +              $object->{$field_name}->expandable_foreign_keys
 | 
	
		
			
				|  |  | +            );
 | 
	
		
			
				|  |  | +            unset($object->{$field_name}->expandable_foreign_keys);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          // Otherwise, just move the expandable foreign keys downwards
 | 
	
		
			
				|  |  | +          else {
 | 
	
		
			
				|  |  | +            $object->expandable_foreign_keys = $object->{$field_name}->expandable_foreign_keys;
 | 
	
		
			
				|  |  | +            unset($object->{$field_name}->expandable_foreign_keys);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Move expandable tables downwards
 | 
	
		
			
				|  |  | +        if (isset($field_value->expandable_tables) and is_array($field_value->expandable_tables)) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // If the current object has it's own expandable tables then merge them
 | 
	
		
			
				|  |  | +          if (isset($object->expandable_tables)) {
 | 
	
		
			
				|  |  | +            $object->expandable_tables = array_merge(
 | 
	
		
			
				|  |  | +              $object->expandable_tables,
 | 
	
		
			
				|  |  | +              $object->{$field_name}->expandable_tables
 | 
	
		
			
				|  |  | +            );
 | 
	
		
			
				|  |  | +            unset($object->{$field_name}->expandable_tables);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          // Otherwise, just move the expandable tables downwards
 | 
	
		
			
				|  |  | +          else {
 | 
	
		
			
				|  |  | +            $object->expandable_tables = $object->{$field_name}->expandable_tables;
 | 
	
		
			
				|  |  | +            unset($object->{$field_name}->expandable_tables);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Move expandable nodes downwards
 | 
	
		
			
				|  |  | +        if (isset($field_value->expandable_nodes) and is_array($field_value->expandable_nodes)) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // If the current object has it's own expandable tables then merge them
 | 
	
		
			
				|  |  | +          if (isset($object->expandable_nodes)) {
 | 
	
		
			
				|  |  | +            $object->expandable_nodes = array_merge(
 | 
	
		
			
				|  |  | +              $object->expandable_nodes,
 | 
	
		
			
				|  |  | +              $object->{$field_name}->expandable_nodes
 | 
	
		
			
				|  |  | +            );
 | 
	
		
			
				|  |  | +            unset($object->{$field_name}->expandable_nodes);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          // Otherwise, just move the expandable tables downwards
 | 
	
		
			
				|  |  | +          else {
 | 
	
		
			
				|  |  | +            $object->expandable_nodes = $object->{$field_name}->expandable_nodes;
 | 
	
		
			
				|  |  | +            unset($object->{$field_name}->expandable_nodes);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Move extended array downwards ----------------------------------
 | 
	
		
			
				|  |  | +  // This tells us what we have expanded (ie: that we succeeded)
 | 
	
		
			
				|  |  | +  // and is needed to remove the entry from the expandable array
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // If there is no expanded field in the current object then check any of the nested objects
 | 
	
		
			
				|  |  | +  // and move it down
 | 
	
		
			
				|  |  |    if (!property_exists($object, 'expanded')) {
 | 
	
		
			
				|  |  | -    //if there's no extended field then go hunting for it
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // It's a nested object if the value is an object
 | 
	
		
			
				|  |  |      foreach ( (array)$object as $field_name => $field_value) {
 | 
	
		
			
				|  |  |        if (is_object($field_value)) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Check if the current nested object has an expanded array
 | 
	
		
			
				|  |  |          if (isset($field_value->expanded)) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          // If so, then move it downwards
 | 
	
		
			
				|  |  |            $object->expanded = $field_value->expanded;
 | 
	
		
			
				|  |  |            unset($field_value->expanded);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  //try again becasue now we might have moved it down
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Check again if there is an expanded field in the current object
 | 
	
		
			
				|  |  | +  // We check again because it might have been moved downwards above
 | 
	
		
			
				|  |  |    if (property_exists($object, 'expanded')) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // If so, then remove the expanded identifier from the correct expandable array
 | 
	
		
			
				|  |  |      $expandable_name = 'expandable_' . $type . 's';
 | 
	
		
			
				|  |  |      if (property_exists($object, $expandable_name) and $object->{$expandable_name}) {
 | 
	
		
			
				|  |  |        $key_to_remove = array_search($object->expanded, $object->{$expandable_name});
 | 
	
		
			
				|  |  |        unset($object->{$expandable_name}[$key_to_remove]);
 | 
	
		
			
				|  |  |        unset($object->expanded);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    else {
 | 
	
		
			
				|  |  | -      // if there is an expandable array then we've reached the base object
 | 
	
		
			
				|  |  | -      // if we get here and don't have anything expanded then something went wrong
 | 
	
		
			
				|  |  | -      //      tripal_report_error('tripal_core', TRIPAL_ERROR,
 | 
	
		
			
				|  |  | -      //        'chado_expand_var: Unable to expand the %type %to_expand',
 | 
	
		
			
				|  |  | -      //        array('%type'=>$type, '%to_expand'=>$to_expand),
 | 
	
		
			
				|  |  | -      //      );
 | 
	
		
			
				|  |  | -    } //end of it we've reached the base object
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  // Finally, Return the object!
 | 
	
		
			
				|  |  |    return $object;
 | 
	
		
			
				|  |  |  }
 |