Browse Source

a functional go loading function totally rewritten from the previous one to run without building the large array that was causing memory problems. also included is the drush commands for setting permissions and preparing after chado installation.

Shawna Spoor 7 years ago
parent
commit
2f21625b83
2 changed files with 431 additions and 366 deletions
  1. 155 41
      tripal/tripal.drush.inc
  2. 276 325
      tripal_chado/api/modules/tripal_chado.cv.api.inc

+ 155 - 41
tripal/tripal.drush.inc

@@ -19,6 +19,35 @@
  *
  * @ingroup tripal_drush
  */
+function tripal_drush_help($command) {
+  switch ($command) {
+
+    // TRIPAL JOBS
+    case 'trp-run-jobs':
+      return dt('Launches pending jobs waiting in the queue.');
+      break;
+    case 'trp-rerun-job':
+      return dt('Rerun a job in the queue.');
+      break;
+    case 'trp-get-currjob':
+      return dt('Returns details about the currently running tripal job including percent complete.');
+      break;
+    // Placeholders for unimplmeneted jobs
+    case 'trp-show-job':
+      break;
+    case 'trp-revert-jobs':
+      break;
+    case 'trp-cancel-job':
+      break;
+    case 'trp-list-jobs':
+      break;
+    case 'trp-prepare-chado':
+      break;
+    case 'trp-set-permissions':
+      break;
+  }
+}
+
 /**
  * Registers a drush command and constructs the full help for that command.
  *
@@ -82,7 +111,20 @@ function tripal_drush_command() {
       'single' => dt('Execute only one queued job'),
     ),
   );
-
+  $items['trp-prepare-chado'] = array(
+    'description' => dt('Prepares a new Tripal installation with content types, requires the username of an administrator to run.'),
+    'arguments'   => array(),
+    'examples' => array(
+      'Standard example' => 'drush trp-prepare-chado --username=administrator',
+    ),
+  );
+  $items['trp-set-permissions'] = array(
+    'description' => dt('Gives view, edit, delete, create priveleges to administrators for all tripal content types.'),
+    'arguments'   => array(),
+    'examples' => array(
+      'Standard example' => 'drush trp-set-permissions --username=administrator',
+    ),
+  );
   return $items;
 }
 
@@ -160,39 +202,6 @@ function drush_tripal_trp_run_jobs() {
   }
 }
 
-
-/**
- * Executes jobs in the Tripal Jobs Queue.
- *
- * Executed when 'drush trp-run-job' is called.
- *
- * @ingroup tripal_drush
- */
-function drush_tripal_trp_run_jobs_install($username) {
-  $parallel = drush_get_option('parallel');
-  $job_id   = drush_get_option('job_id');
-  $max_jobs = drush_get_option('max_jobs', -1);
-  $single   = drush_get_option('single', 0);
-
-  drush_tripal_set_user($username);
-
-  drush_print("\n" . date('Y-m-d H:i:s'));
-  if ($parallel) {
-    drush_print("Tripal Job Launcher (in parallel)");
-    if ($max_jobs !== -1) drush_print("Maximum number of jobs is " . $max_jobs);
-    drush_print("Running as user '$username'");
-    drush_print("-------------------");
-    tripal_launch_job($parallel, $job_id, $max_jobs, $single);
-  }
-  else {
-    drush_print("Tripal Job Launcher");
-    drush_print("Running as user '$username'");
-    drush_print("-------------------");
-    tripal_launch_job(0, $job_id, $max_jobs, $single);
-  }
-}
-
-
 /**
  * Executes jobs in the Tripal Jobs Queue.
  *
@@ -261,13 +270,13 @@ function drush_tripal_trp_get_currjob() {
   foreach ($jobs as $job) {
     $job_pid = $job->pid;
     $output = "Name: " . $job->job_name . "\n" .
-      "Submitted: " . date(DATE_RFC822, $job->submit_date) . "\n" .
-      "Started: " . date(DATE_RFC822, $job->start_time) . "\n" .
-      "Module: " . $job->modulename . "\n" .
-      "Callback: " . $job->callback . "\n" .
-      "Process ID: " . $job->pid . "\n" .
-      "Progress: " . $job->progress . "%\n".
-      "Current Date: " . date('Y-m-d H:i:s') . "\n";
+        "Submitted: " . date(DATE_RFC822, $job->submit_date) . "\n" .
+        "Started: " . date(DATE_RFC822, $job->start_time) . "\n" .
+        "Module: " . $job->modulename . "\n" .
+        "Callback: " . $job->callback . "\n" .
+        "Process ID: " . $job->pid . "\n" .
+        "Progress: " . $job->progress . "%\n".
+        "Current Date: " . date('Y-m-d H:i:s') . "\n";
     drush_print(date('Y-m-d H:i:s'));
     drush_print($output);
   }
@@ -278,3 +287,108 @@ function drush_tripal_trp_get_currjob() {
   //log to the command line with an OK status
   drush_log('Running tripal-current-job', 'ok');
 }
+
+/**
+ * Prepares content types on the site after chado installation.
+ *
+ * Executed when 'drush trp-prepare-chado' is called.
+ *
+ * @ingroup tripal_drush
+ */
+function drush_tripal_trp_prepare_chado() {
+  $user = drush_get_option('user');
+  $uname = drush_get_option('username');
+  if ($user and is_numeric($user)) {
+  }
+  elseif ($user) {
+    print "\nNOTE: Use of the --user argument is deprecated as it conflicts with the --user argument of Drush 7.x. Please now use --username instead.\n\n";
+    $username = $user;
+  }
+  if ($uname) {
+    $username = $uname;
+  }
+
+  drush_tripal_set_user($username);
+
+  print_r("Now preparing the site by creating content types.\n");
+  $prepare = drush_invoke_process('@self', 'php-eval', array("module_load_include('inc', 'tripal_chado', 'includes/setup/tripal_chado.setup'); tripal_chado_prepare_drush_submit();"), array());
+  drush_invoke_process('@self', 'php-eval', array("module_load_include('inc', 'tripal', 'tripal.drush'); drush_tripal_trp_run_jobs_install(" . $username . ");"), array());
+  if (!$prepare) {
+    echo "An error occurred when attempting to install Chado. Please navigate to your new site and finish the installation process from the 'Install Tripal' section as described in the online help, found here http://tripal.info/tutorials/v3.x/installation/tripal \n";
+    exit;
+  }
+}
+
+/**
+ * Sets permissions for the content types on the site.
+ *
+ * Executed when 'drush trp-set-permissions' is called.
+ *
+ * @ingroup tripal_drush
+ */
+function drush_tripal_trp_set_permissions() {
+  $user = drush_get_option('user');
+  $uname = drush_get_option('username');
+  if ($user and is_numeric($user)) {
+  }
+  elseif ($user) {
+    print "\nNOTE: Use of the --user argument is deprecated as it conflicts with the --user argument of Drush 7.x. Please now use --username instead.\n\n";
+    $username = $user;
+  }
+  if ($uname) {
+    $username = $uname;
+  }
+
+  drush_tripal_set_user($username);
+
+  $database_info = FALSE;
+  while (!$database_info) {
+    drush_print(dt(""));
+    drush_print(dt(
+      "To add permissions from the command line the database information is required, please have the database host (127.0.0.1 or localhost), database name, postgres username and postgres user password ready.\n"
+    ));
+    print_r("");
+    $host = drush_prompt(dt('host, like localhost or 127.0.0.1'));
+    $database = drush_prompt(dt('database name'));
+    $postgres_username = drush_prompt(dt('postgres username'));
+    $postgres_password = drush_prompt(dt('postgres password'));
+    drush_print(dt(""));
+    drush_print(dt(
+    "This is the information provided, please review and confirm it is correct: 
+     Database host: $host
+     Database name: $database 
+     Database username: $postgres_username
+     Database user password: $postgres_password
+     "
+    ));
+    $database_info = drush_confirm(dt('Is this information correct?'));
+  }
+  print_r("Adding permissions for the administrator to view, edit, create, and delete all the newly created content types.\n");
+  $permissions = array();
+  $bundles = array();
+  $conn = pg_pconnect("host=$host dbname=$database user=$postgres_username password=$postgres_password");
+  if (!$conn) {
+    echo "An error occurred when attempting to perimssion the administrator. Please navigate to your new site and add permissions to your new content types here admin/people/permissions.\n";
+    exit;
+  }
+  $result = pg_query($conn, "SELECT name FROM tripal_bundle");
+  if (!$result) {
+    echo "An error occurred.\n";
+    exit;
+  }
+
+  while ($row = pg_fetch_row($result)) {
+    array_push($bundles, $row);
+  }
+  foreach ($bundles as $bundles => $bundle) {
+    array_push($permissions, ' view ' . $bundle[0], ' create ' . $bundle[0],
+      ' edit ' . $bundle[0], ' delete ' . $bundle[0]);
+  }
+  $string_permissions = implode(",", $permissions);
+  $args4 = array('administrator', $string_permissions);
+  $options4 = array();
+  drush_invoke_process('@self', 'role-add-perm', $args4, $options4);
+
+  drush_print(dt(""));
+  drush_print(dt("Permissions is now complete."));
+}

+ 276 - 325
tripal_chado/api/modules/tripal_chado.cv.api.inc

@@ -418,8 +418,8 @@ function tripal_update_cvtermpath($cv_id, $job_id = NULL){
  * @param $cvid
  *   The controlled vocabulary ID from the cv table of Chado (i.e. cv.cv_id).
  */
-function tripal_update_cvtermpath_root_loop($rootid, $cvid, &$roots){
-
+function tripal_update_cvtermpath_root_loop($rootid, $cvid, &$roots) {
+  
   // Get's the cvterm record for this "root".
   $ttype = db_select('cvterm', 'cv')
           ->fields('cv', array('cvterm_id'));
@@ -437,23 +437,26 @@ function tripal_update_cvtermpath_root_loop($rootid, $cvid, &$roots){
     }
   }
   // Then add that new entry to the $tree_path.
-  $roots[] =  $term_id;
+  $roots[] = $term_id;
 
   // Descends through the branch starting at this "root" term.
-  $visited = array();
+  $tree_path = array();
+  $matched_rows = array();
+  $possible_start_of_loop = array();
   $depth = 0;
-  tripal_update_cvtermpath_loop($rootid, $rootid, $cvid, $result->cvterm_id, $depth, 0, $visited);
+  tripal_update_cvtermpath_loop($rootid, $rootid, $cvid, $result->cvterm_id, $depth,
+                                0, $tree_path, FALSE, $matched_rows, $possible_start_of_loop, FALSE);
 
   // Get's the children terms of this "root" term and then recursively calls
   // this function making each child root.
   $cterm = db_query(
     'SELECT *
-     FROM cvterm_relationship
-     WHERE object_id = :rootid
+      FROM cvterm_relationship
+      WHERE object_id = :rootid
     ',
     array(':rootid' => $rootid)
   );
-  while($cterm_result = $cterm->fetchAssoc()) {
+  while ($cterm_result = $cterm->fetchAssoc()) {
     tripal_update_cvtermpath_root_loop($cterm_result['subject_id'], $cvid, $roots);
   }
 }
@@ -479,365 +482,313 @@ function tripal_update_cvtermpath_root_loop($rootid, $cvid, &$roots){
  *     -build_id: an string identifier for the child that combines the origin,
  *      child cvterm_id,cv_id, and the type_id.
  *     -depth: the depth that a child was inserted into the cvtermpath table.
+ * @param $possible_loop
+ *    A boolean flag.
+ * @param $matched_row
+ *    An array of rows that are currently in the cvtermpath table that match the 
+ *    build_id of the current term trying to be written to the table
+ * @param $possible_start_of_ loop
+ *    The array of the possible loop item between the current child and the origin. 
+ *    Each element in the array is an associative array with the keys:
+ *     - cvid : $cv_id
+ *     - subject_id: 
+ *     - child_id : $child_id,
+ *     - type_id : $type_id,
+ *     - depth : $depth,
+ * @param $no_loop_skip_test
+ *     A boolean used when the possible loop has been ruled out as a loop.
  * @return multitype:
  */
-$loop_data;
+function tripal_update_cvtermpath_loop(
+  $origin,
+  $child_id,
+  $cv_id,
+  $type_id,
+  $depth,
+  $increment_of_depth,
+  $tree_path,
+  $possible_loop,
+  $matched_rows,
+  $possible_start_of_loop,
+  $no_loop_skip_test) {
 
-function tripal_update_cvtermpath_loop($origin, $child_id, $cv_id, $type_id, $depth,
-                                       $increment_of_depth, $tree_path){
-  // An array of
-  global $loop_data;
-  // Check to see if a row with these values already exists.
-  chado_set_active('chado');
-  $count =  db_query(
-    'SELECT *
-     FROM cvtermpath
-     WHERE cv_id = :cvid
-      AND object_id = :origin
-      AND subject_id = :child_id
-      AND pathdistance = :depth
-    ',
-    array(':cvid' => $cv_id, ':origin' => $origin, ':child_id' => $child_id, ':depth' => $depth)
-  );
-  $count_total = $count->rowCount();
-  // If we've already seen this term then just return, we don't want
-  // to insert it again.
-  if ($count_total > 0) {
-    return $loop_data;
-  }
-  // Build the ID.
-  $term_id = $origin . '|' . $child_id . '|' . $cv_id . '|' . $type_id;
-  // Now check if the most recent entry already exists in the array.
-  if ($increment_of_depth != 0 && empty($loop_data)) {
-    // Search the $tree_path for the new $child_id in the build_id column.
-    foreach ($tree_path as $parent) {
-      // If this child is the same as a parent term that has already been
-      // processed then we have a potential loop.
-      if ($parent['build_id'] == $term_id) {
-        // The loop checker function below.
-        $result_of_loop_checker = tripal_update_cvtermpath_loop_checker($origin,
-          $child_id, $cv_id, $type_id, $depth, $increment_of_depth, 0,
-          $parent, array(), $depth);
-        if (!empty($result_of_loop_checker)) {
-          $loop_data = $result_of_loop_checker;
-          //Find the depth of the loop start by finding it in the array_of_children
-          foreach($tree_path as $children => $child){
-            if($child['build_id'] == $loop_data['build_id']){
-              $loop_location = $child['depth'];
-            }
-          }
-          $array_loop_data = (array)$loop_data;
-          $array_loop_data['depth'] = $loop_location;
-          $loop_data = $array_loop_data;
-          break;
-        }
-      }
-      if (!empty($loop_data)) {
-        return $loop_data;
-      }
-    }
-  }
   // We have not detected a loop, so it's safe to insert the term.
-  $query = db_insert('cvtermpath')
-    ->fields([
-      'object_id' => $origin,
-      'subject_id' => $child_id,
-      'cv_id' => $cv_id,
-      'type_id' => $type_id,
-      'pathdistance' => $depth,
-    ]);
-  $rows = $query->execute();
-  // Then add that new entry to the $tree_path.
-  $tree_path[$increment_of_depth] = [
-    'build_id' => $term_id,
-    'depth' => $depth
-  ];
-  // Get all of the relationships of this child term, and recursively
-  // call the tripal_update_cvtermpath_loop() function to continue
-  // descending down the tree.
-  $query = db_select('cvterm_relationship', 'cvtr')
-    ->fields('cvtr')
-    ->condition('cvtr.object_id', $child_id, '=')
-    ->execute();
-  $cterm_relationships = $query->fetchAll();
-  foreach ($cterm_relationships as $item) {
-    if (!empty($loop_data)) {
-      if ($loop_data['depth'] < $depth) {
-        break;
+  $new_match_rows = array();
+  if (!empty($possible_start_of_loop)) {
+    // Go through each matched_row.
+    if (count($matched_rows) === 1) {
+      // Get the cvtermpath_id and then increment down one row.
+      $cvtermpath_id = (int) $matched_rows[0]->cvtermpath_id;
+      $cvtermpath_id = $cvtermpath_id + 1;
+      chado_set_active('chado');
+      $next_row = db_query(
+        'SELECT *
+          FROM cvtermpath
+          WHERE cvtermpath_id = :cvtermpath_id
+        ',
+        array(':cvtermpath_id' => $cvtermpath_id)
+      );
+      $next_row = $next_row->fetchObject();
+      
+      // If the next row matches the values passed we can't rule out a loop.
+      if (($next_row->type_id === $type_id) &&
+          ($next_row->subject_id === $child_id) &&
+          ($next_row->object_id === $origin) &&
+          ($next_row->cv_id === $cv_id)) {
+        $new_match_rows[] = $next_row;
       }
-      elseif ($loop_data['depth'] > $depth) {
-        $loop_data = NULL;
-        break;
+      elseif (($next_row->type_id === $possible_start_of_loop['type_id']) &&
+              ($next_row->subject_id === $possible_start_of_loop['subject_id']) &&
+              ($next_row->object_id === $possible_start_of_loop['object_id']) &&
+              ($next_row->cv_id === $possible_start_of_loop['cv_id'])) {
+        // The next_row is equal to start of loop, so we've reached the end
+        // and confirmed that this is a loop.
+        $possible_loop == FALSE;
+        $matched_rows = array();
+        tripal_update_cvtermpath_loop_increment($origin, $child_id, $cv_id,
+        $type_id, $depth + 1, $increment_of_depth, $tree_path, $possible_loop,
+        $new_match_rows, $possible_start_of_loop, $no_loop_skip_test);
+
       }
     }
     else {
-      $increment_of_depth++;
-      tripal_update_cvtermpath_loop($origin, $item->subject_id, $cv_id,
-        $item->type_id, $depth + 1, $increment_of_depth, $tree_path);
-    }
-  }
-}
+      foreach ($matched_rows as $matched_row) {
+        // Get the cvtermpath_id and then increment down one row.
+        $cvtermpath_id = (int) $match_row->cvtermpath_id;
+        // Get the cvtermpath_id and then increment down one row.
+        $cvtermpath_id = $cvtermpath_id + 1;
+        chado_set_active('chado');
+        $next_row = db_query(
+          'SELECT *
+            FROM cvtermpath
+            WHERE cvtermpath_id = :cvtermpath_id
+          ',
+          array(':cvtermpath_id' => $cvtermpath_id)
+        );
+        $next_row = $next_row->fetchObject();
+
+        // If the next row matches the values passed we can't rule out a loop.
+        if (($next_row->type_id === $type_id) &&
+            ($next_row->subject_id === $child_id) &&
+            ($next_row->object_id === $origin) &&
+            ($next_row->cv_id === $cv_id)) {
+          $new_match_rows[] = $next_row;
+        }
+        elseif (($next_row->type_id === $possible_start_of_loop['type_id']) &&
+                ($next_row->subject_id === $possible_start_of_loop['subject_id']) &&
+                ($next_row->object_id === $possible_start_of_loop['object_id']) &&
+                ($next_row->cv_id === $possible_start_of_loop['cv_id'])) {
+          // The next_row is equal to start of loop, so we've reached the end
+          // and confirmed that this is a loop.
+          $possible_loop == FALSE;
+          $matched_rows = array();
+          tripal_update_cvtermpath_loop_increment($origin, $child_id, $cv_id,
+          $type_id, $depth + 1, $increment_of_depth, $tree_path, $possible_loop,
+          $new_match_rows, $possible_start_of_loop, $no_loop_skip_test);
 
-/**
- * @param $origin
- * @param $child_id
- * @param $cv_id
- * @param $type_id
- * @param $depth
- * @param $increment_of_depth
- * @param $distance_between_parent_child
- * @param $possible_start_of_loop
- * @param $array_of_possible_loop
- * @param $depth_at_start_of_loop
- *
- * @return bool
- */
-function tripal_update_cvtermpath_loop_checker($origin, $child_id, $cv_id, $type_id,
-    $depth, $increment_of_depth, $distance_between_parent_child, $possible_start_of_loop,
-    $array_of_possible_loop, $depth_at_start_of_loop){
-
-  // Find the child terms of the current term via the relationship taboe.
-  chado_set_active('chado');
-  $query = db_select('cvterm_relationship', 'cvtr')
-    ->fields('cvtr')
-    ->condition('cvtr.object_id', $child_id, '=')
-    ->execute();
-  $cterm_relationships = $query->fetchAll();
-
-  // Iterate through the child terms via the relationships.
-  foreach ($cterm_relationships as $item){
-    // Search the $tree_path for the new $child_id in the build_id column.
-    foreach ($array_of_possible_loop as $parent) {
-      if ($parent['build_id'] === $possible_start_of_loop['build_id']) {
-        // If the search returns something check for a possible loop.
-        if (!empty($parent)) {
-          $result = tripal_update_cvtermpath_loop_checker_traverse($origin, $child_id,
-              $cv_id, $type_id, $depth, $increment_of_depth, $possible_start_of_loop,
-              $array_of_possible_loop, array(), 0);
-          if(!empty($result)){
-            break 2;
-          }
         }
       }
     }
-
-    $increment_of_depth++;
-    $distance_between_parent_child++;
-    $child_id = $origin . '|' . $item->subject_id . '|' . $cv_id . '|' . $item->type_id;
-    $array_of_possible_loop[$distance_between_parent_child] = ['build_id' => $child_id];
-    $result = tripal_update_cvtermpath_loop_checker($origin, $item->subject_id, $cv_id, $item->type_id, $depth + 1, $increment_of_depth, $distance_between_parent_child, $possible_start_of_loop, $array_of_possible_loop, $depth_at_start_of_loop);
-    if($result !== FALSE){
-      return $result;
-    }
-
-  }
-  if (!empty($result)) {
-    return $result;
-  }
-  else {
-    return FALSE;
-  }
-}
-
-function tripal_update_cvtermpath_loop_checker_traverse($origin, $child_id, $cv_id,
-    $type_id, $depth, $increment_of_depth, $possible_start_of_loop, $array_of_possible_loop,
-    $traverse_of_loop, $increment) {
-
-  chado_set_active('chado');
-  $query = db_select('cvterm_relationship', 'cvtr')
-    ->fields('cvtr')
-    ->condition('cvtr.object_id', $child_id, '=')
-    ->execute();
-  $cterm = $query->fetchAll();
-
-  foreach ($cterm as $item) {
-    if ($array_of_possible_loop === $traverse_of_loop) {
-      //Report the loop.
-      $loop_found = end($array_of_possible_loop);
-      break;
+    // If $match_rows is empty there is no loop.
+    if (empty($new_match_rows)) {
+      $possible_loop == FALSE;
+      $matched_rows = array();
+      unset($new_match_rows);
+      $no_loop_skip_test = TRUE;
+      // There is not loop so pass it back the possible_start_of_loop info
+      // and a flag telling it to skip the loop check.
+      tripal_update_cvtermpath_loop_increment($possible_start_of_loop->subject_id,
+      $possible_start_of_loop->child_id, $possible_start_of_loop->cvid,
+      $possible_start_of_loop->type_id, $possible_start_of_loop->depth,
+      $increment_of_depth, $tree_path, $possible_loop, $matched_rows,
+      $possible_start_of_loop, $no_loop_skip_test);
     }
-    elseif ($array_of_possible_loop != $traverse_of_loop) {
-      $increment_of_depth++;
-      $increment++;
-      $child_id = $origin . '|' . $item->subject_id . '|' . $cv_id . '|' . $item->type_id;
-      $traverse_of_loop[$increment] = ['build_id' => $child_id];
-      $result = tripal_update_cvtermpath_loop_checker_traverse($origin,
-          $item->subject_id, $cv_id, $item->type_id, $depth + 1,
-          $increment_of_depth, $possible_start_of_loop, $array_of_possible_loop,
-          $traverse_of_loop, $increment);
-      if ($result !== FALSE) {
-        return $result;
-      }
+    // If $match_rows is not empty we need to keep trying rows.
+    else {
+      tripal_update_cvtermpath_loop_increment($origin, $child_id, $cv_id,
+      $type_id, $depth + 1, $increment_of_depth, $tree_path, $possible_loop,
+      $match_rows, $possible_start_of_loop, $no_loop_skip_test);
     }
   }
-  if ($loop_found) {
-    return $loop_found;
-  }
-  else {
-    return FALSE;
-
+  elseif ($possible_loop === FALSE) {
+    tripal_update_cvtermpath_loop_increment($origin, $child_id, $cv_id,
+    $type_id, $depth + 1, $increment_of_depth, $tree_path, $possible_loop,
+    $matched_rows, $possible_start_of_loop, $no_loop_skip_test);
   }
 }
-/*
+
+/**
  *
  * @param $origin
- * @param $subject_id
- * @param $cv_idxkcd
+ *   The root terms cvterm_id.
+ * @param $child_id
+ *   The cvterm_id of the current child term.  The child term is a descendent
+ *   of the origin.
+ * @param $cv_id
+ *   The controlled vocabulary ID from the cv table of Chado (i.e. cv.cv_id).
  * @param $type_id
+ *   The relationship type between the origin term and the child.
  * @param $depth
+ *   The depth of the recursion.
+ * @param $increment_of_depth.
+ *   An integer ??
+ * @param $tree_path.
+ *   The array of every term between the current child and the origin. Each
+ *   element in the array is an associative array with the keys:
+ *     -build_id: an string identifier for the child that combines the origin,
+ *      child cvterm_id,cv_id, and the type_id.
+ *     -depth: the depth that a child was inserted into the cvtermpath table.
+ * @param $possible_loop
+ *    A boolean flag.
+ * @param $matched_row
+ *    An array of rows that are currently in the cvtermpath table that match the 
+ *    build_id of the current term trying to be written to the table
+ * @param $possible_start_of_ loop
+ *    The array of the possible loop item between the current child and the origin. 
+ *    Each element in the array is an associative array with the keys:
+ *     - cvid : $cv_id
+ *     - subject_id: 
+ *     - child_id : $child_id,
+ *     - type_id : $type_id,
+ *     - depth : $depth,
+ * @param $no_loop_skip_test
+ *     A boolean used when the possible loop has been ruled out as a loop.
  * @return multitype:
+ */
+function tripal_update_cvtermpath_loop_increment(
+  $origin,
+  $child_id,
+  $cv_id,
+  $type_id,
+  $depth,
+  $increment_of_depth,
+  $tree_path,
+  $possible_loop,
+  $matched_rows,
+  &$possible_start_of_loop,
+  $no_loop_skip_test) {
 
-function tripal_update_cvtermpath_loop($origin, $child_id, $cv_id, $type_id, $depth){
-  // Variables and arrays needed for loop checking.
-  $tree_path;
-  $array_of_possible_loop;
-  $possible_start_of_loop;
-  $distance_between_parent_child;
-  $increment_of_depth;
-
-
-  chado_set_active('chado');
-  $count =  db_query(
-    'SELECT *
-     FROM cvtermpath
-     WHERE cv_id = :cvid
-      AND object_id = :origin
-      AND subject_id = :child_id
-      AND pathdistance = :depth
-    ',
-    array(':cvid' => $cv_id, ':origin' => $origin, ':child_id' => $child_id, ':depth' => $depth)
-  );
-  $count_total = $count->rowCount();
-
-  //Loop check
-  chado_set_active('chado');
-  $loop = db_query(
-    'SELECT *
-     FROM cvtermpath
-     WHERE cv_id = :cvid
-      AND object_id = :origin
-      AND subject_id = :child_id
-      AND type_id = :type_id
-    ',
-    array(':cvid' => $cv_id, ':origin' => $origin, ':child_id' => $child_id, ':type_id' => $type_id,)
-  );
-  $loop_check = $loop->rowCount();
-
-  //watchdog('debug', '<pre>tripal_ds_preprocess_TripalEntity $rows ' . print_r($rows, TRUE) . '</pre>');
-  /*if(!empty($rows)){
-    foreach($rows as $row){
-      tripal_update_cvtermpath_loop_check($origin, $child_id, $cv_id, $type_id, $depth, $row->cvtermpath_id, 0);
+  // Check to see if a row with these values already exists.
+  if ($possible_loop === FALSE && empty($possible_start_of_loop)) {
+    chado_set_active('chado');
+    $count = db_query(
+      'SELECT *
+        FROM cvtermpath
+        WHERE cv_id = :cvid
+        AND object_id = :origin
+        AND subject_id = :child_id
+        AND pathdistance = :depth
+      ',
+      array(
+        ':cvid' => $cv_id,
+        ':origin' => $origin,
+        ':child_id' => $child_id,
+        ':depth' => $depth
+      )
+    );
+    $count_total = $count->rowCount();
+    if ($count_total > 0) {
+      return $count;
     }
-  }
-  else {*/
-  //If no loop proceed.
-  /*try{
-    if($count_total == 0) {
-      chado_set_active('chado');
-
+    // Build the ID.
+    $term_id = $origin . '|' . $child_id . '|' . $cv_id . '|' . $type_id;
+
+    if ($no_loop_skip_test === FALSE) {
+      // Now check if the most recent entry already exists in the array.
+      if ($increment_of_depth != 0) {
+        // Search the $tree_path for the new $child_id in the build_id column.
+        foreach ($tree_path as $parent) {
+          // If this child is the same as a parent term that has already been
+          // processed then we have a potential loop.
+          if ($parent['build_id'] == $term_id) {
+            // Tell the function this is a possible loop and to stop writing to the table.
+            $possible_loop = TRUE;
+            // Find all the results in the table that might be the start of the loop.
+            $matching_rows = db_query(
+              'SELECT *
+              FROM cvtermpath
+              WHERE cv_id = :cvid
+              AND object_id = :origin
+              AND subject_id = :child_id
+              AND type_id = :type_id
+              ',
+              array(
+                ':cvid' => $cv_id,
+                ':origin' => $origin,
+                ':child_id' => $child_id,
+                ':type_id' => $type_id
+              )
+            );
+            $matched_rows = $matching_rows->fetchAll();
+            $possible_start_of_loop = array(
+              'cvid' => $cv_id,
+              'subject_id' => $origin,
+              'child_id' => $child_id,
+              'type_id' => $type_id,
+              'depth' => $depth,
+            );
+          }
+        }
+      }
+    
       $query = db_insert('cvtermpath')
-        ->fields(array(
+        ->fields([
           'object_id' => $origin,
           'subject_id' => $child_id,
           'cv_id' => $cv_id,
           'type_id' => $type_id,
           'pathdistance' => $depth,
-        ));
+        ]);
       $rows = $query->execute();
-    }
-    if ($loop_check == 0) {
-      chado_set_active('chado');
 
-      $query = db_select('cvterm_relationship', 'cvtr')
-        ->fields('cvtr')
-        ->condition('cvtr.object_id', $child_id, '=')
-        ->execute();
-      $cterm = $query->fetchAll();
-
-      foreach ($cterm as $item) {
-        //watchdog('debug', '<pre>tripal_ds_preprocess_TripalEntity $item ' . print_r($item, TRUE) . '</pre>');
-        tripal_update_cvtermpath_loop($origin, $item->subject_id, $cv_id, $item->type_id, $depth + 1);
-      };
-      //}
+      // Then add that new entry to the $tree_path.
+      $tree_path[$increment_of_depth] = [
+        'build_id' => $term_id,
+        'depth' => $depth
+      ];
     }
-  }
-  catch(Exception $e){
-    watchdog_exception('tripal_ds', $e);
-    return FALSE;
-  }
+    // Reset to FALSE  and empty variable if passed in as TRUE.
+    $no_loop_skip_test == FALSE;
+    $possible_start_of_loop = array();
 
-  return 1;
-
-}
-*/
-/**
- *
- * @param $origin
- * @param $subject_id
- * @param $cv_id
- * @param $type_id
- * @param $depth
- * @return multitype:
+    // Get all of the relationships of this child term, and recursively
+    // call the tripal_update_cvtermpath_loop() function to continue
+    // descending down the tree.
+    $query = db_select('cvterm_relationship', 'cvtr')
+      ->fields('cvtr')
+      ->condition('cvtr.object_id', $child_id, '=')
+      ->execute();
+    $cterm_relationships = $query->fetchAll();
 
-function tripal_update_cvtermpath_loop_check($origin, $child_id, $cv_id, $type_id, $depth, $cvtermpath_id, $loop_count, $loop_check, $object_id){
-  //Store the
-
-  //Check if the passed parameters match any of the items in the loop_check array.
-  if(!empty($loop_check)){
-    foreach($loop_check as $item){
-        if ($item['type_id'] = $type_id){
-          if($item['subject_id'] = $child_id){
-            if($item['object_id'] = $object_id){
-              //Loop found, roll back all rows until $cvtermpath_id-1 (last correct entry)
-              // and step into the next loop
-            }
-          }
-        }
+    foreach ($cterm_relationships as $item) {
+      $increment_of_depth++;
+      tripal_update_cvtermpath_loop_increment($origin, $item->subject_id, $cv_id,
+        $item->type_id, $depth + 1, $increment_of_depth, $tree_path, $possible_loop,
+        $matched_rows, $possible_start_of_loop, $no_loop_skip_test);
     }
   }
-  $loop_count + 1;
-
-  chado_set_active('chado');
-  $count =  db_query(
-    'SELECT *
-     FROM cvtermpath
-     WHERE cv_id = :cvid AND object_id = :origin
-       AND subject_id = :child_id
-       AND pathdistance = :depth
-    ',
-    array(':cvid' => $cv_id, ':origin' => $origin, ':child_id' => $child_id, ':depth' => $depth)
-  );
-  $count_total = $count->rowCount();
-
-  if ($count_total == 0) {
-    chado_set_active('chado');
-    $query = db_insert('cvtermpath')
-      ->fields(array(
-        'object_id' => $origin,
-        'subject_id' => $child_id,
-        'cv_id' => $cv_id,
-        'type_id' => $type_id,
-        'pathdistance' => $depth,
-      ));
-    $rows = $query->execute();
-    $cterm = array();
+  elseif ($possible_loop === FALSE && !empty($possible_start_of_loop)) {
+    // This means a loop has been identified and the recursive call can move
+    // on to the next item and skip the rest of this run.
+    return $possible_start_of_loop;
+  }
+  elseif ($possible_loop === TRUE) {
+    // Get all of the relationships of this child term, and recursively
+    // call the tripal_update_cvtermpath_loop() function to continue
+    // descending down the tree.
     $query = db_select('cvterm_relationship', 'cvtr')
       ->fields('cvtr')
-      ->condition('cvtr.object_id', $child_id, '=' )
+      ->condition('cvtr.object_id', $child_id, '=')
       ->execute();
-    $cterm = $query->fetchAll();
-
-    foreach ($cterm as $item) {
-      $loop_check[$loop_count]= $item;
-      tripal_update_cvtermpath_loop_check($origin, $item->subject_id, $cv_id, $item->type_id, $depth + 1, $loop_count, $loop_check, $item->object_id);
-    };
+    $cterm_relationships = $query->fetchAll();
+    foreach ($cterm_relationships as $item) {
+      $increment_of_depth++;
+      tripal_update_cvtermpath_loop($origin, $item->subject_id, $cv_id,
+        $item->type_id, $depth + 1, $increment_of_depth, $tree_path, $possible_loop,
+        $matched_rows, $possible_start_of_loop, $no_loop_skip_test);
+    }
   }
-
-
-  return 1;
-
 }
- */
 
 /**
  * Adds a controlled vocabular to the CV table of Chado.