tripal_bulk_loader.loader.inc 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. <?php
  2. /**
  3. * Add Loader Job Form
  4. *
  5. * This form is meant to be included on the node page to allow users to submit/re-submit
  6. * loading jobs
  7. */
  8. function tripal_bulk_loader_add_loader_job_form ($form_state, $node) {
  9. $form = array();
  10. $form['nid'] = array(
  11. '#type' => 'hidden',
  12. '#value' => $node->nid,
  13. );
  14. $form['file'] = array(
  15. '#type' => 'hidden',
  16. '#value' => $node->file
  17. );
  18. $form['job_id'] = array(
  19. '#type' => 'hidden',
  20. '#value' => $node->job_id,
  21. );
  22. $form['submit'] = array(
  23. '#type' => 'submit',
  24. '#value' => ($node->job_id) ? 'Re-Submit Job' : 'Submit Job',
  25. );
  26. $form['submit-cancel'] = array(
  27. '#type' => ($node->job_id)? 'submit' : 'hidden',
  28. '#value' => 'Cancel Job',
  29. );
  30. return $form;
  31. }
  32. /**
  33. * Add Loader Job Form (Submit)
  34. */
  35. function tripal_bulk_loader_add_loader_job_form_submit ($form, $form_state) {
  36. global $user;
  37. if (preg_match('/Submit Job/', $form_state['values']['op'])) {
  38. //Submit Tripal Job
  39. $job_args[1] = $form_state['values']['nid'];
  40. if (is_readable($form_state['values']['file'])) {
  41. $fname = basename($form_state['values']['file']);
  42. $job_id = tripal_add_job("Bulk Loading Job: $fname",'tripal_bulk_loader', 'tripal_bulk_loader_load_data', $job_args, $user->uid);
  43. // add job_id to bulk_loader node
  44. $record = node_load($form_state['values']['nid']);
  45. $record->job_id = $job_id;
  46. drupal_write_record('tripal_bulk_loader', $record, 'nid');
  47. // Add Sync Features Job
  48. tripal_add_job('Sync all features','tripal_feature',
  49. 'tripal_feature_sync_features',$job_args,$user->uid);
  50. } else {
  51. drupal_set_message("Can not open ".$form_state['values']['file'].". Job not scheduled.");
  52. }
  53. } elseif (preg_match('/Re-Submit Job/', $form_state['values']['op'])) {
  54. tripal_jobs_rerun($form_state['values']['job_id']);
  55. } elseif (preg_match('/Cancel Job/', $form_state['values']['op'])) {
  56. tripal_jobs_cancel($form_state['values']['job_id']);
  57. }
  58. }
  59. /**
  60. * Tripal Bulk Loader
  61. *
  62. * This is the function that's run by tripal_launch_jobs to bulk load chado data.
  63. * @param $nid
  64. * The Node ID of the bulk loading job node to be loaded. All other needed data is expected to be
  65. * in the node (ie: template ID and file)
  66. *
  67. * Note: Instead of returning a value this function updates the tripal_bulk_loader.status and
  68. * Enters errors into tripal_bulk_loader_errors if they are encountered.
  69. */
  70. function tripal_bulk_loader_load_data($nid) {
  71. $node = node_load($nid);
  72. print "Template: ".$node->template->name." (".$node->template_id.")\n";
  73. print "File: ".$node->file."\n";
  74. // Prep Work ==================================================================================
  75. // Generate default values array
  76. $default_data = array();
  77. $field2column = array();
  78. $record2priority = array();
  79. foreach ($node->template->template_array as $priority => $record_array) {
  80. if (!is_array($record_array)) { continue; }
  81. foreach ($record_array['fields'] as $field_index => $field_array) {
  82. $default_data[$priority]['table'] = $record_array['table'];
  83. $default_data[$priority]['mode'] = ($record_array['mode']) ? $record_array['mode'] : 'insert';
  84. $record2priority[$record_array['record_id']] = $priority;
  85. if (preg_match('/table field/', $field_array['type'])) {
  86. $default_data[$priority]['values_array'][$field_array['field']] = '';
  87. $default_data[$priority]['need_further_processing'] = TRUE;
  88. $field2column[$priority][$field_array['field']] = $field_array['spreadsheet column'];
  89. } elseif (preg_match('/constant/', $field_array['type'])) {
  90. $default_data[$priority]['values_array'][$field_array['field']] = $field_array['constant value'];
  91. } elseif (preg_match('/foreign key/', $field_array['type'])) {
  92. $default_data[$priority]['values_array'][$field_array['field']] = array();
  93. $default_data[$priority]['values_array'][$field_array['field']]['foreign record'] = $field_array['foreign key'];
  94. $default_data[$priority]['need_further_processing'] = TRUE;
  95. } else {
  96. print 'WARNING: Unsupported type: '. $field_array['type'] . ' for ' . $table . '.' . $field_array['field']."!\n";
  97. }
  98. } // end of foreach field
  99. } //end of foreach record
  100. //print "\nDefault Values Array: ".print_r($default_data, TRUE)."\n";
  101. //print "\nField to Column Mapping: ".print_r($field2column, TRUE)."\n";
  102. // Parse File adding records as we go ========================================================
  103. $file_handle = fopen($node->file, 'r');
  104. if (preg_match('/(t|true|1)/', $node->file_has_header)) { fgets($file_handle, 4096); }
  105. $num_records = 0;
  106. $num_lines = 0;
  107. $num_errors = 0;
  108. while (!feof($file_handle)) {
  109. $line = array();
  110. $raw_line = fgets($file_handle, 4096);
  111. $raw_line = trim($raw_line);
  112. $line = preg_split("/\t/", $raw_line);
  113. $num_lines++;
  114. $data = $default_data;
  115. foreach ($data as $priority => $table_data) {
  116. $table = $table_data['table'];
  117. $values = $table_data['values_array'];
  118. if ($table_data['need_further_processing']) {
  119. $values = tripal_bulk_loader_add_spreadsheetdata_to_values ($values, $line, $field2column[$priority]);
  120. $values = tripal_bulk_loader_add_foreignkey_to_values($values, $data, $record2priority);
  121. }
  122. // add new values array into the data array
  123. $data[$priority]['values_array'] = $values;
  124. // first check if it already exists
  125. $exists = tripal_core_chado_select($table, array_keys($values), $values, array('has_record'=>TRUE));
  126. if ($exists) {
  127. if (!preg_match('/select/',$table_data['mode'])) {
  128. watchdog('T_bulk_loader',
  129. 'Record already exists in %table: %record',
  130. array('%table' => $table, '%record' => tripal_bulk_loader_flatten_array($values)),
  131. 'WATCHDOG_WARNING'
  132. );
  133. }
  134. } elseif ($exists > 1) {
  135. watchdog('T_bulk_loader',
  136. 'More than 1 record exists in %table: %record',
  137. array('%table' => $table, '%record' => tripal_bulk_loader_flatten_array($values)),
  138. 'WATCHDOG_WARNING'
  139. );
  140. } else {
  141. // if it doesn't exist already then insert it
  142. if (preg_match('/insert/',$table_data['mode'])) {
  143. $success = tripal_core_chado_insert($table, $values);
  144. if (!$success) {
  145. watchdog('T_bulk_loader',
  146. 'Unable to insert the following record into %table: %record',
  147. array('%table' => $table, '%record' => tripal_bulk_loader_flatten_array($values)),
  148. 'WATCHDOG_ERROR'
  149. );
  150. }
  151. }
  152. }// end of if/not record exists
  153. } // end of foreach table in default data array
  154. } //end of foreach line of file
  155. }
  156. /**
  157. * This function adds the file data to the values array
  158. *
  159. * @param $values
  160. * The default values array -contains all constants
  161. * @param $line
  162. * An array of values for the current line
  163. * @param $field2column
  164. * An array mapping values fields to line columns
  165. * @return
  166. * Supplemented values array
  167. */
  168. function tripal_bulk_loader_add_spreadsheetdata_to_values ($values, $line, $field2column) {
  169. foreach ($values as $field => $value) {
  170. if (is_array($value)) { continue; }
  171. $column = $field2column[$field] - 1;
  172. if ($line[$column] OR (!$values[$field])) {
  173. $values[$field] = $line[$column];
  174. }
  175. }
  176. return $values;
  177. }
  178. /**
  179. * Handles foreign keys in the values array.
  180. *
  181. * Specifically, if the value for a field is an array then it is assumed that the array contains
  182. * the name of the record whose values array should be substituted here. Thus the foreign
  183. * record is looked up and the values array is substituted in.
  184. *
  185. */
  186. function tripal_bulk_loader_add_foreignkey_to_values($values, $data, $record2priority) {
  187. foreach ($values as $field => $value) {
  188. if (is_array($value)) {
  189. $foreign_record = $value['foreign record'];
  190. $foreign_priority = $record2priority[$foreign_record];
  191. $foreign_values = $data[$foreign_priority]['values_array'];
  192. //add to current values array
  193. $values[$field] = $foreign_values;
  194. }
  195. }
  196. return $values;
  197. }
  198. /**
  199. * Flattens an array up to two levels
  200. * Used for printing of arrays without taking up much space
  201. */
  202. function tripal_bulk_loader_flatten_array ($values) {
  203. $flattened_values = array();
  204. foreach ($values as $k => $v) {
  205. if (is_array($v)) {
  206. $vstr = array();
  207. foreach ($v as $vk => $vv) {
  208. if (strlen($vv) > 20) {
  209. $vstr[] = $vk .'=>'. substr($vv, 0, 20) . '...';
  210. } else {
  211. $vstr[] = $vk .'=>'. $vv;
  212. }
  213. }
  214. $v = '{'. implode(',',$vstr) .'}';
  215. } elseif (strlen($v) > 20) {
  216. $v = substr($v, 0, 20) . '...';
  217. }
  218. $flattened_values[] = $k .'=>'. $v;
  219. }
  220. return implode(', ',$flattened_values);
  221. }