tripal_bulk_loader.loader.inc 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245
  1. <?php
  2. /**
  3. * @file
  4. * Handles the actual loading of data.
  5. *
  6. * @ingroup tripal_bulk_loader
  7. */
  8. /**
  9. * Add Loader Job Form
  10. *
  11. * This form is meant to be included on the node page to allow users to
  12. * submit/re-submit loading jobs
  13. *
  14. * @ingroup tripal_bulk_loader
  15. */
  16. function tripal_bulk_loader_add_loader_job_form($form, &$form_state, $node) {
  17. $form = [];
  18. // --notify--
  19. if ($node->job_status == 'Loading...') {
  20. drupal_set_message(t("The Loading Summary only updates at the end of each constant set.
  21. Although records may have already been inserted, they won't be available until the
  22. current constant set is full loaded and no errors are encountered.", []), 'warning');
  23. }
  24. $form['nid'] = [
  25. '#type' => 'hidden',
  26. '#value' => $node->nid,
  27. ];
  28. $form['file'] = [
  29. '#type' => 'hidden',
  30. '#value' => $node->file,
  31. ];
  32. $form['job_id'] = [
  33. '#type' => 'hidden',
  34. '#value' => $node->job_id,
  35. ];
  36. $form['submit'] = [
  37. '#type' => 'submit',
  38. '#value' => ($node->job_id) ? 'Re-Submit Job' : 'Submit Job',
  39. ];
  40. $form['submit-cancel'] = [
  41. '#type' => ($node->job_id) ? 'submit' : 'hidden',
  42. '#value' => 'Cancel Job',
  43. ];
  44. if ($node->keep_track_inserted) {
  45. $form['submit-revert'] = [
  46. '#type' => ($node->job_id) ? 'submit' : 'hidden',
  47. '#value' => 'Revert',
  48. ];
  49. }
  50. return $form;
  51. }
  52. /**
  53. * Add Loader Job Form (Submit)
  54. *
  55. * @ingroup tripal_bulk_loader
  56. */
  57. function tripal_bulk_loader_add_loader_job_form_submit($form, $form_state) {
  58. global $user;
  59. if (preg_match('/Submit Job/', $form_state['values']['op'])) {
  60. //Submit Tripal Job
  61. $job_args[1] = $form_state['values']['nid'];
  62. if (is_readable($form_state['values']['file'])) {
  63. $fname = basename($form_state['values']['file']);
  64. $job_id = tripal_add_job("Bulk Loading Job: $fname", 'tripal_bulk_loader', 'tripal_bulk_loader_load_data', $job_args, $user->uid);
  65. // add job_id to bulk_loader node
  66. $success = db_update('tripal_bulk_loader')->fields([
  67. 'job_id' => $job_id,
  68. 'job_status' => 'Submitted to Queue',
  69. ])->condition('nid', $form_state['values']['nid'])->execute();
  70. }
  71. else {
  72. drupal_set_message(t("Can not open %file. Job not scheduled.", ['%file' => $form_state['values']['file']]));
  73. }
  74. }
  75. elseif (preg_match('/Re-Submit Job/', $form_state['values']['op'])) {
  76. tripal_rerun_job($form_state['values']['job_id']);
  77. $success = db_update('tripal_bulk_loader')->fields([
  78. 'job_status' => 'Submitted to Queue',
  79. ])->condition('nid', $form_state['values']['nid'])->execute();
  80. }
  81. elseif (preg_match('/Cancel Job/', $form_state['values']['op'])) {
  82. $success = db_update('tripal_bulk_loader')->fields([
  83. 'job_status' => 'Job Cancelled',
  84. ])->condition('nid', $form_state['values']['nid'])->execute();
  85. tripal_cancel_job($form_state['values']['job_id']);
  86. }
  87. elseif (preg_match('/Revert/', $form_state['values']['op'])) {
  88. // Remove the records from the database that were already inserted
  89. $resource = db_query('SELECT * FROM {tripal_bulk_loader_inserted} WHERE nid=:nid ORDER BY tripal_bulk_loader_inserted_id DESC', [':nid' => $form_state['values']['nid']]);
  90. while ($r = $resource->fetchObject()) {
  91. $ids = preg_split('/,/', $r->ids_inserted);
  92. db_query('DELETE FROM {' . $r->table_inserted_into . '} WHERE ' . $r->table_primary_key . ' IN (' . $r->ids_inserted . ')')->execute();
  93. $result = db_query('SELECT true as present FROM {' . $r->table_inserted_into . '} WHERE ' . $r->table_primary_key . ' IN (' . $r->ids_inserted . ')')->fetchObject();
  94. if (!$result->present) {
  95. drupal_set_message(t('Successfully Removed data Inserted into the %tableto table.', ['%tableto' => $r->table_inserted_into]));
  96. db_query('DELETE FROM {tripal_bulk_loader_inserted} WHERE tripal_bulk_loader_inserted_id=:id', [':id' => $r->tripal_bulk_loader_inserted_id])->execute();
  97. }
  98. else {
  99. drupal_set_message(t('Unable to remove data Inserted into the %tableto table!', ['%tableto' => $r->table_inserted_into]), 'error');
  100. }
  101. }
  102. // reset status
  103. $success = db_update('tripal_bulk_loader')->fields([
  104. 'job_status' => 'Reverted -Data Deleted',
  105. ])->condition('nid', $form_state['values']['nid'])->execute();
  106. }
  107. }
  108. /**
  109. * Tripal Bulk Loader
  110. *
  111. * This is the function that's run by tripal_launch_jobs to bulk load chado
  112. * data.
  113. *
  114. * @param $nid
  115. * The Node ID of the bulk loading job node to be loaded. All other needed
  116. * data is expected to be in the node (ie: template ID and file)
  117. *
  118. * Note: Instead of returning a value this function updates the
  119. * tripal_bulk_loader.status. Errors are thrown through watchdog and can be
  120. * viewed at admin/reports/dblog.
  121. *
  122. * @ingroup tripal_bulk_loader
  123. */
  124. function tripal_bulk_loader_load_data($nid, $job_id) {
  125. // ensure no timeout
  126. drupal_set_time_limit(0);
  127. // set the status of the job (in the node not the tripal jobs)
  128. db_update('tripal_bulk_loader')
  129. ->fields(['job_status' => 'Loading...'])
  130. ->condition('nid', $nid)
  131. ->execute();
  132. $node = node_load($nid);
  133. print "Template: " . $node->template->name . " (" . $node->template_id . ")\n";
  134. // Determine the total number of non-blank lines in the file.
  135. $total_lines = 0;
  136. $handle = fopen($node->file, "r");
  137. while (!feof($handle)) {
  138. $line = fgets($handle);
  139. $line = trim($line);
  140. if (empty($line)) {
  141. continue;
  142. } // skips blank lines
  143. $total_lines++;
  144. }
  145. fclose($handle);
  146. // do not count header line in the non-blank line count
  147. if (($total_lines) and (preg_match('/(t|true|1)/', $node->file_has_header))) {
  148. $total_lines--;
  149. }
  150. // Correct for files with a single line and no enter character.
  151. $total_lines = ($total_lines == 0) ? 1 : $total_lines;
  152. print "File: " . $node->file . " (" . $total_lines . " lines with data)\n";
  153. //print "\nClearing all prepared statements from previous runs of this loader...\n";
  154. //tripal_core_chado_clear_prepared('_'.$node->nid.'_');
  155. // Prep Work ==================================================================================
  156. print "\nPreparing to load...\n";
  157. $loaded_without_errors = TRUE;
  158. // Generate default values array
  159. $default_data = [];
  160. $field2column = [];
  161. $record2priority = [];
  162. $tables = [];
  163. $template_array = $node->template->template_array;
  164. // first build the record2priority array
  165. foreach ($template_array as $priority => $record_array) {
  166. $record2priority[$record_array['record_id']] = $priority;
  167. }
  168. //
  169. foreach ($template_array as $priority => $record_array) {
  170. if (!is_array($record_array)) {
  171. continue;
  172. }
  173. // Add tables being inserted into to a list to be treated differently
  174. // this is used to acquire locks on these tables
  175. if (preg_match('/insert/', $record_array['mode'])) {
  176. $tables[$record_array['table']] = $record_array['table'];
  177. }
  178. // iterate through each of the fields for the current record and
  179. // set the default_data array
  180. foreach ($record_array['fields'] as $field_index => $field_array) {
  181. $default_data[$priority]['table'] = $record_array['table'];
  182. $default_data[$priority]['mode'] = ($record_array['mode']) ? $record_array['mode'] : 'insert';
  183. $default_data[$priority]['select_if_duplicate'] = ($record_array['select_if_duplicate']) ? $record_array['select_if_duplicate'] : 0;
  184. $default_data[$priority]['update_if_duplicate'] = ($record_array['update_if_duplicate']) ? $record_array['update_if_duplicate'] : 0;
  185. $default_data[$priority]['disabled'] = ($record_array['disable']) ? $record_array['disable'] : 0;
  186. $default_data[$priority]['optional'] = ($record_array['optional']) ? $record_array['optional'] : 0;
  187. $default_data[$priority]['select_optional'] = ($record_array['select_optional']) ? $record_array['select_optional'] : 0;
  188. $default_data[$priority]['record_id'] = $record_array['record_id'];
  189. $default_data[$priority]['required'][$field_array['field']] = $field_array['required'];
  190. $one = $default_data[$priority];
  191. if (isset($field_array['regex'])) {
  192. $default_data[$priority]['regex_transform'][$field_array['field']] = $field_array['regex'];
  193. }
  194. $two = $default_data[$priority];
  195. if (preg_match('/table field/', $field_array['type'])) {
  196. $default_data[$priority]['values_array'][$field_array['field']] = '';
  197. $default_data[$priority]['need_further_processing'] = TRUE;
  198. $field2column[$priority][$field_array['field']] = $field_array['spreadsheet column'];
  199. }
  200. elseif (preg_match('/constant/', $field_array['type'])) {
  201. $default_data[$priority]['values_array'][$field_array['field']] = $field_array['constant value'];
  202. }
  203. elseif (preg_match('/foreign key/', $field_array['type'])) {
  204. $default_data[$priority]['values_array'][$field_array['field']] = [];
  205. $default_data[$priority]['need_further_processing'] = TRUE;
  206. $default_data[$priority]['values_array'][$field_array['field']]['foreign record']['record'] = $field_array['foreign key'];
  207. // Add in the FK / Referral table
  208. $fk_priority = $record2priority[$field_array['foreign key']];
  209. $fk_table = $template_array[$fk_priority]['table'];
  210. $default_data[$priority]['values_array'][$field_array['field']]['foreign record']['table'] = $fk_table;
  211. // Add in the FK / Referral field
  212. // for backwards compatibility we need to get the FK relationship to find
  213. // out what field we're joining on. For templates created using a
  214. // previous version it was assumed that the FK field was always the field to join
  215. if (!array_key_exists('foreign field', $field_array)) {
  216. $tbl_description = chado_get_schema($record_array['table']);
  217. foreach ($tbl_description['foreign keys'] as $key_table => $key_array) {
  218. if ($key_table == $fk_table) {
  219. foreach ($key_array['columns'] as $left_field => $right_field) {
  220. if ($left_field == $field_array['field']) {
  221. $field_array['foreign field'] = $right_field;
  222. }
  223. }
  224. }
  225. }
  226. }
  227. $default_data[$priority]['values_array'][$field_array['field']]['foreign record']['field'] = $field_array['foreign field'];
  228. }
  229. else {
  230. print 'WARNING: Unsupported type: ' . $field_array['type'] . ' for ' . $table . '.' . $field_array['field'] . "!\n";
  231. }
  232. $three = $default_data[$priority];
  233. } // end of foreach field
  234. } //end of foreach record
  235. ///////////////////////////////////////////////
  236. // For each set of constants
  237. ///////////////////////////////////////////////
  238. print "Loading...\n";
  239. $original_default_data = $default_data;
  240. $group_index = 0;
  241. $total_num_groups = sizeof($node->constants);
  242. // If there are no constant sets and no exposed fields
  243. // then create an empty constant set so loader runs
  244. if ($total_num_groups == 0 && empty($node->exposed_fields)) {
  245. $node->constants = [
  246. 0 => [],
  247. ];
  248. $total_num_groups = 1;
  249. }
  250. foreach ($node->constants as $group_id => $set) {
  251. // revert default data array for next set of constants
  252. $default_data = $original_default_data;
  253. $group_index++;
  254. // Add constants
  255. if (!empty($set)) {
  256. print "Constants:\n";
  257. foreach ($set as $priority => $record) {
  258. foreach ($record as $field_id => $field) {
  259. print "\t- " . $field['chado_table'] . '.' . $field['chado_field'] . ' = ' . $field['value'] . "\n";
  260. if ($default_data[$priority]['table'] == $field['chado_table']) {
  261. if (isset($default_data[$priority]['values_array'][$field['chado_field']])) {
  262. if (isset($field2column[$priority][$field['chado_field']])) {
  263. $field2column[$priority][$field['chado_field']] = $field['value'];
  264. }
  265. else {
  266. $default_data[$priority]['values_array'][$field['chado_field']] = $field['value'];
  267. }
  268. }
  269. else {
  270. print "ERROR: Template has changed after constants were assigned!\n";
  271. tripal_bulk_loader_throw_error('Template has changed after constants were assigned', [], TRIPAL_NOTICE);
  272. exit(1);
  273. }
  274. }
  275. else {
  276. print "ERROR: Template has changed after constants were assigned!\n";
  277. tripal_bulk_loader_throw_error('Template has changed after constants were assigned', [], TRIPAL_NOTICE);
  278. exit(1);
  279. }
  280. }
  281. }
  282. }
  283. // Open File
  284. print "\tPreparing to load the current constant set...\n";
  285. print "\t\tOpen File...\n";
  286. try {
  287. $file = new SplFileObject($node->file, 'r');
  288. } catch (Exception $e) {
  289. tripal_bulk_loader_throw_error('Could not open file %file',
  290. ['%file' => $node->file], TRIPAL_ERROR);
  291. return;
  292. }
  293. // Set defaults
  294. $header = '';
  295. if (preg_match('/(t|true|1)/', $node->file_has_header)) {
  296. $file->next();
  297. $header = $file->current();
  298. }
  299. $num_records = 0;
  300. $num_lines = 0;
  301. $num_errors = 0;
  302. $interval = intval($total_lines * 0.0001);
  303. if ($interval == 0) {
  304. $interval = 1;
  305. }
  306. // Start Transaction
  307. $savepoint = '';
  308. switch (variable_get('tripal_bulk_loader_transactions', 'row')) {
  309. case "none":
  310. break;
  311. case "all":
  312. print "\t\tStart Transaction...\n";
  313. $TRANSACTION = db_transaction();
  314. $transactions = TRUE;
  315. break;
  316. case "row":
  317. print "\t\tStart Transaction...\n";
  318. $TRANSACTION = db_transaction();
  319. $transactions = TRUE;
  320. $new_transaction_per_row = TRUE;
  321. break;
  322. }
  323. // Disable triggers
  324. $triggers_disabled = FALSE;
  325. if ($transactions AND variable_get('tripal_bulk_loader_disable_triggers', TRUE)) {
  326. print "\t\tDefer Constraints...\n";
  327. $triggers_disabled = TRUE;
  328. chado_query("SET CONSTRAINTS ALL DEFERRED");
  329. }
  330. // Acquire Locks
  331. if ($transactions) {
  332. print "\t\tAcquiring Table Locks...\n";
  333. $lockmode = variable_get('tripal_bulk_loader_lock', 'ROW EXCLUSIVE');
  334. foreach ($tables as $table) {
  335. print "\t\t\t$lockmode for $table\n";
  336. chado_query("LOCK TABLE {" . $table . "} IN " . $lockmode . " MODE");
  337. }
  338. }
  339. print "\tLoading the current constant set...\n";
  340. tripal_bulk_loader_progress_bar(0, $total_lines);
  341. while (!$file->eof()) {
  342. $file->next();
  343. $raw_line = $file->current();
  344. $raw_line = trim($raw_line);
  345. if (empty($raw_line)) {
  346. continue;
  347. } // skips blank lines
  348. $line = explode("\t", $raw_line);
  349. $num_lines++;
  350. // update the job status every 1% of lines processed for the current group
  351. if ($node->job_id and $num_lines % $interval == 0) {
  352. // percentage of lines processed for the current group
  353. $group_progress = round(($num_lines / $total_lines) * 100);
  354. // don't show progress for the last line, that is printed at the end of this function
  355. if ($num_lines < $total_lines) {
  356. tripal_bulk_loader_progress_bar($num_lines, $total_lines);
  357. }
  358. // percentage of lines processed for all groups
  359. // <previous group index> * 100 + <current group progress>
  360. // --------------------------------------------------------
  361. // <total number of groups>
  362. // For example, if you were in the third group of 3 constant sets
  363. // and had a group percentage of 50% then the job progress would be
  364. // (2*100 + 50%) / 3 = 250%/3 = 83%
  365. $job_progress = round(((($group_index - 1) * 100) + $group_progress) / $total_num_groups);
  366. tripal_set_job_progress($node->job_id, $job_progress);
  367. }
  368. $data = $default_data;
  369. // iterate through each record and process the line
  370. $data_keys = array_keys($data);
  371. foreach ($data_keys as $priority) {
  372. $options = [
  373. 'field2column' => $field2column,
  374. 'record2priority' => $record2priority,
  375. 'line' => $line,
  376. 'line_num' => $num_lines,
  377. 'group_index' => $group_index,
  378. 'node' => $node,
  379. 'nid' => $node->nid,
  380. ];
  381. // execute all records that are not disabled
  382. $no_errors = FALSE;
  383. if (array_key_exists($priority, $data) and
  384. array_key_exists('disabled', $data[$priority]) and
  385. $data[$priority]['disabled'] == 0) {
  386. $no_errors = process_data_array_for_line($priority, $data, $default_data, $options);
  387. }
  388. else {
  389. // set status to true for skipped records
  390. $no_errors = TRUE;
  391. }
  392. tripal_bulk_loader_progress_file_track_job($job_id, $no_errors);
  393. $failed = FALSE;
  394. if ($no_errors == FALSE) {
  395. // Encountered an error
  396. if ($transactions) {
  397. $TRANSACTION->rollback();
  398. }
  399. tripal_bulk_loader_finish_loading($node->nid, FALSE);
  400. break;
  401. }
  402. } // end of foreach table in default data array
  403. tripal_bulk_loader_progress_file_track_job($job_id, FALSE, TRUE);
  404. if ($failed) {
  405. $TRANSACTION->rollback();
  406. tripal_bulk_loader_finish_loading($node->nid, FALSE);
  407. break;
  408. }
  409. else {
  410. // Row inserted successfully
  411. if ($transactions && $new_transaction_per_row) {
  412. // commit current transaction and start a new one
  413. unset($TRANSACTION);
  414. $TRANSACTION = db_transaction();
  415. }
  416. }
  417. } //end of foreach line of file
  418. // END Transaction
  419. if ($transactions) {
  420. unset($TRANSACTION);
  421. }
  422. if ($failed) {
  423. $loaded_without_errors = FALSE;
  424. break;
  425. }
  426. tripal_bulk_loader_progress_bar($num_lines, $total_lines);
  427. tripal_bulk_loader_progress_file_track_job($job_id, FALSE, FALSE, TRUE);
  428. } //end of foreach constant set
  429. tripal_bulk_loader_finish_loading($node->nid, $loaded_without_errors);
  430. }
  431. /**
  432. * Process the data array for a given line
  433. *
  434. * @param $addt
  435. * Requires: field2column', 'record2priority', 'line', 'line_num',
  436. * 'group_index', 'node', 'nid'
  437. *
  438. * @ingroup tripal_bulk_loader
  439. */
  440. function process_data_array_for_line($priority, &$data, &$default_data, $addt) {
  441. //$time_start = microtime(true);
  442. $table_data = $data[$priority];
  443. $addt = (object) $addt;
  444. $no_errors = TRUE;
  445. $table = $table_data['table'];
  446. $values = $table_data['values_array'];
  447. // populate the values array with real value either from the input data file line
  448. // or from the foreign key / referral record
  449. if (array_key_exists('need_further_processing', $table_data) and $table_data['need_further_processing']) {
  450. if (array_key_exists($priority, $addt->field2column)) {
  451. $values = tripal_bulk_loader_add_spreadsheetdata_to_values($values, $addt->line, $addt->field2column[$priority]);
  452. }
  453. $values = tripal_bulk_loader_add_foreignkey_to_values($table_data, $values, $data, $addt->record2priority, $addt->nid, $priority, $default_data);
  454. }
  455. $values = tripal_bulk_loader_regex_tranform_values($values, $table_data, $addt->line);
  456. if (!$values) {
  457. //tripal_bulk_loader_throw_error('Line ' . $addt->line_num . ' Regex:<pre>' . print_r($values, TRUE) . print_r($table_data, TRUE) . '</pre>' . '</pre>', array(), TRIPAL_NOTICE);
  458. }
  459. // get the table description
  460. $table_desc = chado_get_schema($table);
  461. if (!$table_desc) {
  462. $msg = "Tripal does not know about the table named '%table'. If this is a custom table,
  463. please define it first";
  464. tripal_bulk_loader_throw_error($msg, ['%table' => $table], TRIPAL_ERROR);
  465. $data[$priority]['error'] = TRUE;
  466. return;
  467. }
  468. // Check that template required fields are present. if a required field is
  469. // missing and this is an optional record then just return. otherwise raise
  470. // an error
  471. $skip_optional = 0;
  472. foreach ($table_data['required'] as $field => $required) {
  473. if ($required) {
  474. // check if the field has no value (or array is empty)
  475. if (!isset($values[$field]) or
  476. (is_array($values[$field]) and count($values[$field]) == 0)) {
  477. // check if the record is optional. For backwards compatiblity we need to
  478. // check if the 'mode' is set to 'optional'
  479. if ($table_data['optional'] or preg_match('/optional/', $table_data['mode']) or
  480. $table_data['select_optional']) {
  481. $skip_optional = 1;
  482. // set the values array to be empty since we all required fields are
  483. // optional and we can't do a select/insert so we don't want to keep
  484. // the values if this record is used in a later FK relationship.
  485. $values = [];
  486. }
  487. else {
  488. $msg = "Line " . $addt->line_num . ' "' . $table_data['record_id'] .
  489. '" (' . $table_data['mode'] . ') Missing template required value: ' . $table . '.' . $field;
  490. tripal_bulk_loader_throw_error($msg, [], TRIPAL_WARNING);
  491. $data[$priority]['error'] = TRUE;
  492. $no_errors = FALSE;
  493. }
  494. }
  495. }
  496. }
  497. // for an insert, check that all database required fields are present in the values array
  498. // we check for 'optional' in the mode for backwards compatibility. The 'optional'
  499. // mode used to be a type of insert
  500. if (!$skip_optional and (preg_match('/insert/', $table_data['mode']) or
  501. preg_match('/optional/', $table_data['mode']))) {
  502. // Check all database table required fields are set
  503. $fields = $table_desc['fields'];
  504. foreach ($fields as $field => $def) {
  505. // a field is considered missing if it cannot be null and there is no default
  506. // value for it or it is not of type 'serial'
  507. if (array_key_exists('not null', $def) and $def['not null'] == 1 and // field must have a value
  508. !array_key_exists($field, $values) and // there is not a value for it
  509. !array_key_exists('default', $def) and // there is no default for it
  510. strcmp($def['type'], 'serial') != 0) { // it is not a 'serial' type column
  511. $msg = "Line " . $addt->line_num . ' ' . $table_data['record_id'] .
  512. ' (' . $table_data['mode'] . ') Missing Database Required Value: ' . $table . '.' . $field;
  513. tripal_bulk_loader_throw_error($msg, [], TRIPAL_ERROR);
  514. $data[$priority]['error'] = TRUE;
  515. $no_errors = FALSE;
  516. }
  517. }
  518. }
  519. // add updated values array into the data array
  520. $data[$priority]['values_array'] = $values;
  521. // if there was an error already -> don't insert
  522. if (array_key_exists('error', $data[$priority]) and $data[$priority]['error']) {
  523. tripal_bulk_loader_throw_error('Skipping processing of %table due to previous errors', ['%table' => $table], TRIPAL_NOTICE);
  524. return $no_errors;
  525. }
  526. // skip optional fields
  527. if ($skip_optional) {
  528. // SPF -- Commented out the following line. This state is intentional due
  529. // to the loader setup and and is not an error. If informational it
  530. // prints too much to the terminal.
  531. // tripal_bulk_loader_throw_error('Skipping an optional record (%record)',array('%record'=>$table_data['record_id']),TRIPAL_NOTICE);
  532. return $no_errors;
  533. }
  534. // check if it is already inserted
  535. if (array_key_exists('inserted', $table_data) and $table_data['inserted']) {
  536. // SPF -- Commented out the following line. This state is intentional due
  537. // to the loader setup and and is not an error. If informational it
  538. // prints too much to the terminal.
  539. // tripal_bulk_loader_throw_error('Skipping %record since it is already inserted',array('%record'=>$table_data['record_id']),TRIPAL_NOTICE);
  540. return $no_errors;
  541. }
  542. // check if it is already selected, if so, just get the value stored in
  543. // the default_data array
  544. if (array_key_exists('selected', $table_data) and $table_data['selected']) {
  545. $data[$priority]['values_array'] = $default_data[$priority]['values_array'];
  546. // SPF -- Commented out the following line. This state is intentional due
  547. // to the loader setup and and is not an error. If informational it
  548. // prints too much to the terminal.
  549. // tripal_bulk_loader_throw_error('%record was already selected thus we are just returning the values previously selected.',array('%record'=>$table_data['record_id']),TRIPAL_NOTICE);
  550. return $no_errors;
  551. }
  552. // make sure we have some value in the select_if_duplicate and update_if_duplicate options
  553. if (!array_key_exists('select_if_duplicate', $table_data)) {
  554. $table_data['select_if_duplicate'] = 0;
  555. }
  556. if (!array_key_exists('update_if_duplicate', $table_data)) {
  557. $table_data['update_if_duplicate'] = 0;
  558. }
  559. // if "select if duplicate" is enabled then check to ensure unique constraint is not violated.
  560. // If it is violated then simply return, the record already exists in the database.
  561. // We check for "insert_unique" for backwards compatibilty but that mode no longer exists
  562. $data[$priority]['is_duplicate'] = 0;
  563. if (preg_match('/insert_unique/', $table_data['mode']) or
  564. $table_data['select_if_duplicate'] == 1 or
  565. $table_data['update_if_duplicate'] == 1) {
  566. $options = ['is_duplicate' => TRUE, 'print_errors' => TRUE];
  567. $duplicate = chado_select_record($table, array_keys($table_desc['fields']), $values, $options);
  568. // if this is a duplicate then substitute the values in the table_data array so
  569. // that for future records that may depend on this one, they can get the values needed
  570. if ($duplicate and is_array($duplicate) and count($duplicate) == 1) {
  571. $dup_record = $duplicate[0];
  572. // save the duplicate record for later. If this is an update_if_duplicate
  573. // then we'll need this record as the match
  574. $data[$priority]['is_duplicate'] = (array) $dup_record;
  575. // if all we have is one field then we will just use the value returned
  576. // rather than create an array of values. This way it will prevent
  577. // the tripal_core_chado_(select|insert|update) from recursing on
  578. // foreign keys and make the loader go faster.
  579. if (count((array) $dup_record) == 1) {
  580. foreach ($dup_record as $key => $value) {
  581. $data[$priority]['values_array'] = $value;
  582. }
  583. }
  584. // if we have multiple fields returned then we need to set the values
  585. // the new array.
  586. else {
  587. // convert object to array
  588. $new_values = [];
  589. foreach ($dup_record as $key => $value) {
  590. $new_values[$key] = $value;
  591. }
  592. $data[$priority]['values_array'] = $new_values;
  593. }
  594. // return if this is a select_if_duplicate
  595. if ($table_data['select_if_duplicate'] == 1) {
  596. // SPF -- Commented out the following line. This state is intentional due
  597. // to the loader setup and and is not an error. If informational it
  598. // prints too much to the terminal.
  599. // tripal_bulk_loader_throw_error('Simply returning values for %record since it was already inserted',array('%record'=>$table_data['record_id']),TRIPAL_NOTICE);
  600. return $no_errors;
  601. }
  602. }
  603. }
  604. else {
  605. # TODO: what to do if there are more than one value returned when
  606. # checking for a duplicate?
  607. }
  608. if (!preg_match('/select/', $table_data['mode'])) {
  609. // Use prepared statement?
  610. if (variable_get('tripal_bulk_loader_prepare', TRUE)) {
  611. $options = ['statement_name' => 'record_' . $addt->nid . '_' . $priority];
  612. if (($addt->line_num > 1 && $addt->group_index == 1) OR $addt->group_index > 1) {
  613. //$options['is_prepared'] = TRUE;
  614. }
  615. }
  616. else {
  617. $options = [];
  618. }
  619. // Skip chado_insert_record() built-in validation?
  620. if (variable_get('tripal_bulk_loader_skip_validation', FALSE)) {
  621. $options['skip_validation'] = TRUE;
  622. }
  623. if ($table_data['update_if_duplicate'] == 1) {
  624. if (array_key_exists('statement_name', $options)) {
  625. $options['statement_name'] = 'upd_' . $options['statement_name'];
  626. }
  627. // This should have been set on the first round of inserts for this record
  628. $match = $data[$priority]['is_duplicate'];
  629. // However, sometimes there is a pre-existing record before the loader starts
  630. // Thus check that this value is set and if not, then generate a match array
  631. // based on the unique keys for this record.
  632. if (empty($match)) {
  633. $match = [];
  634. // First check to see if we have fields for the primary key
  635. foreach ($table_desc['primary key'] as $k_field) {
  636. if (!empty($values[$k_field])) {
  637. $match[$k_field] = $values[$k_field];
  638. }
  639. }
  640. // Otherwise check the fields that are part of the unique key
  641. if (empty($match)) {
  642. foreach ($table_desc['unique keys'] as $u_keys) {
  643. foreach ($u_keys as $u_field) {
  644. if (!empty($values[$u_field])) {
  645. $match[$u_field] = $values[$u_field];
  646. }
  647. }
  648. }
  649. }
  650. }
  651. if (!empty($match)) {
  652. // Now we need to check if it already exists via a select
  653. $results = chado_select_record($table, array_keys($table_desc['fields']), $match, ['print_errors' => TRUE]);
  654. // If not then insert
  655. if (empty($results)) {
  656. $options['statement_name'] = 'ins_' . $options['statement_name'];
  657. $options['print_errors'] = TRUE;
  658. $record = chado_insert_record($table, $values, $options);
  659. }
  660. else {
  661. $options['return_record'] = TRUE;
  662. $options['print_errors'] = TRUE;
  663. $record = chado_update_record($table, $match, $values, $options);
  664. }
  665. }
  666. else {
  667. $msg = "\nLine " . $addt->line_num . ' ' . $table_data['record_id'] . ' (' .
  668. $table_data['mode'] . ') Unable to update record since none of the unique key or primary key fields were available ' .
  669. ' where values:' . print_r($values, TRUE);
  670. tripal_bulk_loader_throw_error($msg, [], TRIPAL_ERROR);
  671. $data[$priority]['error'] = TRUE;
  672. $no_errors = FALSE;
  673. }
  674. }
  675. else {
  676. $options['print_errors'] = TRUE;
  677. $record = chado_insert_record($table, $values, $options);
  678. }
  679. // if the insert was not successful
  680. if (!$record) {
  681. $msg = "\nLine " . $addt->line_num . ' ' . $table_data['record_id'] . ' (' .
  682. $table_data['mode'] . ') Unable to insert record into ' . $table .
  683. ' where values:' . print_r($values, TRUE);
  684. tripal_bulk_loader_throw_error($msg, [], TRIPAL_ERROR);
  685. $data[$priority]['error'] = TRUE;
  686. $no_errors = FALSE;
  687. }
  688. // if the insert was succesful
  689. else {
  690. // if mode=insert_once then ensure we only insert it once
  691. if (preg_match('/insert_once/', $table_data['mode'])) {
  692. $default_data[$priority]['inserted'] = TRUE;
  693. }
  694. // add to tripal_bulk_loader_inserted
  695. if ($addt->node->keep_track_inserted) {
  696. $insert_record = db_query(
  697. "SELECT * FROM {tripal_bulk_loader_inserted} WHERE table_inserted_into=:table AND nid=:nid",
  698. [
  699. ':table' => $table,
  700. 'nid' => $addt->nid,
  701. ])->fetchObject();
  702. if ($insert_record) {
  703. $insert_record->ids_inserted .= ',' . $record[$table_desc['primary key'][0]];
  704. drupal_write_record('tripal_bulk_loader_inserted', $insert_record, 'tripal_bulk_loader_inserted_id');
  705. //print 'Update: '.print_r($insert_record,TRUE)."\n";
  706. //return $no_errors;
  707. }
  708. else {
  709. $insert_record = [
  710. 'nid' => $addt->nid,
  711. 'table_inserted_into' => $table,
  712. 'table_primary_key' => $table_desc['primary key'][0],
  713. 'ids_inserted' => $record[$table_desc['primary key'][0]],
  714. ];
  715. //print 'New: '.print_r($insert_record,TRUE)."\n";
  716. $success = drupal_write_record('tripal_bulk_loader_inserted', $insert_record);
  717. //return $no_errors;
  718. }//end of if insert record
  719. }// end of if keeping track of records inserted
  720. // substitute the values array for the primary key if it exists
  721. // and is a single field
  722. if (array_key_exists('primary key', $table_desc)) {
  723. if (count($table_desc['primary key']) == 1) {
  724. $pkey_field = $table_desc['primary key'][0];
  725. $data[$priority]['values_array'] = $record[$pkey_field];
  726. }
  727. }
  728. else {
  729. //add changes back to values array
  730. $data[$priority]['values_array'] = $record;
  731. $values = $record;
  732. }
  733. } //end of if insert was successful
  734. }
  735. // perform a select
  736. else {
  737. // get the matches for this select
  738. $matches = [];
  739. if (is_array($values) and count($values) > 0) {
  740. $matches = chado_select_record($table, array_keys($table_desc['fields']), $values, ['print_errors' => TRUE]);
  741. }
  742. // if the record doesn't exist and it's not optional then generate an error
  743. if (count($matches) == 0) {
  744. // No record on select
  745. if ($table_data['select_optional'] != 1) {
  746. $msg = "\nLine " . $addt->line_num . ' ' . $table_data['record_id'] . ' (' . $table_data['mode'] . ') No Matching record in ' . $table . ' where values:' . print_r($values, TRUE);
  747. tripal_bulk_loader_throw_error($msg, [], TRIPAL_ERROR);
  748. $data[$priority]['error'] = TRUE;
  749. $no_errors = FALSE;
  750. }
  751. // there is no match and select optional is turned on, so we want to set
  752. // the values to empty for any records with an FK relationship on this one
  753. else {
  754. $data[$priority]['values_array'] = NULL;
  755. }
  756. }
  757. // if we have more than one record matching and this select isn't optional then fail
  758. if (count($matches) > 1) {
  759. if ($table_data['select_optional'] != 1) {
  760. $msg = "\nLine " . $addt->line_num . ' ' . $table_data['record_id'] . ' (' . $table_data['mode'] . ') Too many matching records in ' . $table . ' where values:' . print_r($values, TRUE);
  761. tripal_bulk_loader_throw_error($msg, [], TRIPAL_WARNING);
  762. $data[$priority]['error'] = TRUE;
  763. $no_errors = FALSE;
  764. }
  765. // there are too many matches and this is an optional select so set
  766. // the values to empty for any records with an FK relationship on this one
  767. else {
  768. $data[$priority]['values_array'] = NULL;
  769. }
  770. }
  771. // if mode=select_once then ensure we only select it once
  772. if (preg_match('/select_once/', $table_data['mode'])) {
  773. $default_data[$priority]['selected'] = TRUE;
  774. // save the pkey
  775. if (array_key_exists('primary key', $table_desc)) {
  776. $new_values = [];
  777. foreach ($matches[0] as $key => $value) {
  778. $new_values[$key] = $value;
  779. }
  780. $default_data[$priority]['values_default'] = $new_values;
  781. }
  782. }
  783. }
  784. return $no_errors;
  785. }
  786. /**
  787. * This function adds the file data to the values array
  788. *
  789. * @param $values
  790. * The default values array -contains all constants
  791. * @param $line
  792. * An array of values for the current line
  793. * @param $field2column
  794. * An array mapping values fields to line columns
  795. *
  796. * @return
  797. * Supplemented values array
  798. *
  799. * @ingroup tripal_bulk_loader
  800. */
  801. function tripal_bulk_loader_add_spreadsheetdata_to_values($values, $line, $field2column) {
  802. foreach ($values as $field => $value) {
  803. if (is_array($value)) {
  804. continue;
  805. }
  806. $column = $field2column[$field] - 1;
  807. if ($column < 0) {
  808. continue;
  809. }
  810. if (preg_match('/\S+/', $line[$column])) {
  811. $values[$field] = $line[$column];
  812. }
  813. else {
  814. unset($values[$field]);
  815. }
  816. }
  817. return $values;
  818. }
  819. /**
  820. * Handles foreign keys in the values array.
  821. *
  822. * Specifically, if the value for a field is an array then it is assumed that
  823. * the array contains the name of the record whose values array should be
  824. * substituted here. Thus the foreign record is looked up and the values array
  825. * is substituted in.
  826. *
  827. * @ingroup tripal_bulk_loader
  828. */
  829. function tripal_bulk_loader_add_foreignkey_to_values($table_array, $values, $data, $record2priority, $nid, $priority, $default_data) {
  830. // iterate through each field in the $values arrray and
  831. // substitute any values for FK / referring fields
  832. foreach ($values as $field => $value) {
  833. // if the field value is an array then it is an FK
  834. if (is_array($value)) {
  835. // get the name and priority of the foreign record
  836. $foreign_record = $value['foreign record']['record'];
  837. $foreign_priority = $record2priority[$foreign_record];
  838. $foreign_table = $value['foreign record']['table'];
  839. $foreign_field = $value['foreign record']['field'];
  840. // get the values of the foreign record and substitute those for the values
  841. $foreign_values = $data[$foreign_priority]['values_array'];
  842. // check to see if we have any default values in the $default_data array
  843. // these were populated from select statements that only need to run once
  844. // so we can reuse the values from those previous selects.
  845. if (array_key_exists($foreign_priority, $default_data) and
  846. array_key_exists('values_default', $default_data[$foreign_priority]) and
  847. array_key_exists($foreign_field, $default_data[$foreign_priority]['values_default'])) {
  848. $values[$field] = $default_data[$foreign_priority]['values_default'][$foreign_field];
  849. continue;
  850. }
  851. // if the field in the Referral records is in a FK relationship with
  852. // this field then we can simply keep the value we have
  853. $tbl_description = chado_get_schema($table_array['table']);
  854. if ($tbl_description and
  855. array_key_exists('foreign keys', $tbl_description) and
  856. array_key_exists($foreign_table, $tbl_description['foreign keys']) and
  857. array_key_exists($field, $tbl_description['foreign keys'][$foreign_table]['columns']) and
  858. $foreign_field == $tbl_description['foreign keys'][$foreign_table]['columns'][$field]) {
  859. $values[$field] = $foreign_values;
  860. }
  861. // if the field in the Referral records is not in an FK relationship
  862. // with this field then we we have to get the requested value, we must
  863. // return only a single value
  864. else {
  865. // if the current value of the referral records is a non-array then this
  866. // is the primary key, we can use it to select the value we need.
  867. $fk_description = chado_get_schema($foreign_table);
  868. if (!is_array($foreign_values)) {
  869. // if we have a value then use it to get the field we need
  870. if ($foreign_values) {
  871. $fvalues = [$fk_description['primary key'][0] => $foreign_values];
  872. $columns = [$foreign_field];
  873. $options = ['statement_name' => 'pk_' . $foreign_table];
  874. $options['print_errors'] = TRUE;
  875. $record = chado_select_record($foreign_table, $columns, $fvalues, $options);
  876. if ($record) {
  877. $values[$field] = $record[0]->$foreign_field;
  878. }
  879. else {
  880. unset($values[$field]);
  881. }
  882. }
  883. // if we don't have a value then there's nothing we can do so
  884. // set this value to nothing as well
  885. else {
  886. unset($values[$field]);
  887. }
  888. }
  889. // if the current value is an array and our field is not in it, then
  890. // we need to select a value for our field.
  891. else {
  892. $fvalues = $foreign_values;
  893. $columns = [$foreign_field];
  894. $options = ['statement_name' => 'blk_' . $nid . $priority . $foreign_table];
  895. $options['print_errors'] = TRUE;
  896. $record = chado_select_record($foreign_table, $columns, $fvalues, $options);
  897. if ($record) {
  898. $values[$field] = $record[0]->$foreign_field;
  899. }
  900. else {
  901. unset($values[$field]);
  902. }
  903. } // end else from: if (!is_array($foreign_values) ...
  904. } // end else from: if ($tbl_description ...
  905. } // end if(is_array($value)) ...
  906. } // end foreach ($values ...
  907. // return the updated field values
  908. return $values;
  909. }
  910. /**
  911. * Uses a supplied regex to transform spreadsheet values
  912. *
  913. * @param $values
  914. * The select/insert values array for the given table
  915. * @param $table_data
  916. * The data array for the given table
  917. *
  918. * @ingroup tripal_bulk_loader
  919. */
  920. function tripal_bulk_loader_regex_tranform_values($values, $table_data, $line) {
  921. if (!array_key_exists('regex_transform', $table_data) or
  922. empty($table_data['regex_transform']) or
  923. !array_key_exists('regex_transform', $table_data) or
  924. !is_array($table_data['regex_transform'])) {
  925. return $values;
  926. }
  927. //tripal_core_report_error('T_bulk_loader', TRIPAL_NOTICE,'Regex Transformation:<pre>'.print_r($table_data['regex_transform'], TRUE).'</pre>', array());
  928. foreach ($table_data['regex_transform'] as $field => $regex_array) {
  929. if (!array_key_exists('replace', $regex_array) or
  930. !array_key_exists('pattern', $regex_array) or
  931. !is_array($regex_array['replace'])) {
  932. continue;
  933. }
  934. // Check for <#column:\d+#> notation
  935. // if present replace with that column in the current line
  936. foreach ($regex_array['replace'] as $key => $replace) {
  937. if (preg_match_all('/<#column:(\d+)#>/', $replace, $matches)) {
  938. foreach ($matches[1] as $k => $column_num) {
  939. $replace = preg_replace('/' . $matches[0][$k] . '/', $line[$column_num - 1], $replace);
  940. }
  941. $regex_array['replace'][$key] = $replace;
  942. }
  943. }
  944. // do the full replacement
  945. $old_value = $values[$field];
  946. $new_value = preg_replace($regex_array['pattern'], $regex_array['replace'], $old_value);
  947. $values[$field] = $new_value;
  948. if ($values[$field] === '') {
  949. unset($values[$field]);
  950. }
  951. //print 'Now:'.$values[$field]."\n";
  952. }
  953. return $values;
  954. }
  955. /**
  956. * Flattens an array up to two levels
  957. * Used for printing of arrays without taking up much space
  958. *
  959. * @ingroup tripal_bulk_loader
  960. */
  961. function tripal_bulk_loader_flatten_array($values) {
  962. $flattened_values = [];
  963. foreach ($values as $k => $v) {
  964. if (is_array($v)) {
  965. $vstr = [];
  966. foreach ($v as $vk => $vv) {
  967. if (drupal_strlen($vv) > 20) {
  968. $vstr[] = $vk . '=>' . drupal_substr($vv, 0, 20) . '...';
  969. }
  970. else {
  971. $vstr[] = $vk . '=>' . $vv;
  972. }
  973. }
  974. $v = '{' . implode(',', $vstr) . '}';
  975. }
  976. elseif (drupal_strlen($v) > 20) {
  977. $v = drupal_substr($v, 0, 20) . '...';
  978. }
  979. $flattened_values[] = $k . '=>' . $v;
  980. }
  981. return implode(', ', $flattened_values);
  982. }
  983. /**
  984. * Used to display loader progress to the user
  985. *
  986. * @ingroup tripal_bulk_loader
  987. */
  988. function tripal_bulk_loader_progress_bar($current = 0, $total = 100, $size = 50) {
  989. $new_bar = FALSE;
  990. $mem = memory_get_usage();
  991. // First iteration
  992. if ($current == 0) {
  993. $new_bar = TRUE;
  994. fputs(STDOUT, "Progress:\n");
  995. }
  996. // Percentage round off for a more clean, consistent look
  997. $percent = sprintf("%.02f", round(($current / $total) * 100, 2));
  998. // percent indicator must be four characters, if shorter, add some spaces
  999. for ($i = strlen($percent); $i <= 4; $i++) {
  1000. $percent = ' ' . $percent;
  1001. }
  1002. $total_size = $size + $i + 3 + 2;
  1003. $place = 0;
  1004. // if it's not first go, remove the previous bar
  1005. if (!$new_bar) {
  1006. for ($place = $total_size; $place > 0; $place--) {
  1007. // echo a backspace (hex:08) to remove the previous character
  1008. //echo "\x08";
  1009. }
  1010. }
  1011. // output the progess bar as it should be
  1012. // Start with a border
  1013. echo '[';
  1014. for ($place = 0; $place <= $size; $place++) {
  1015. // output "full" spaces if this portion is completed
  1016. if ($place <= ($current / $total * $size)) {
  1017. echo '|';
  1018. }
  1019. else {
  1020. // Otherwise empty space
  1021. echo '-';
  1022. }
  1023. }
  1024. // End with a border
  1025. echo ']';
  1026. // end a bar with a percent indicator
  1027. echo " $percent%. ($current of $total) Memory: $mem\r";
  1028. // if it's the end, add a new line
  1029. if ($current == $total) {
  1030. echo "\n";
  1031. }
  1032. }
  1033. /**
  1034. * Keep track of progress in file rather then database
  1035. *
  1036. * This provides an alternative method to keep track of progress that doesn't
  1037. * require the database. It was needed because you can't switch databases
  1038. * within a transaction... Waiting until the end of a constant set is much too
  1039. * long to wait for any indication that things are working.
  1040. *
  1041. * Each line represents a line processed in the loading file. Each period (.)
  1042. * represents a successfully inserted record.
  1043. *
  1044. * @param $job_id
  1045. * The ID of the current tripal job
  1046. * @param $record_added
  1047. * A boolean indicated whether a record was added successfully
  1048. * @param $line_complete
  1049. * A boolean indicating whether the current line is finished
  1050. * @param $close
  1051. * A boolean indicating that the file should be closed
  1052. *
  1053. * @ingroup tripal_bulk_loader
  1054. */
  1055. function tripal_bulk_loader_progress_file_track_job($job_id, $record_added, $line_complete = FALSE, $close = FALSE) {
  1056. // retrieve the file handle
  1057. $file_handle = variable_get('tripal_bulk_loader_progress_file_handle', NULL);
  1058. // open file for reading if not already
  1059. if (!$file_handle) {
  1060. $file_handle = fopen('/tmp/tripal_bulk_loader_progress-' . $job_id . '.out', 'w');
  1061. variable_set('tripal_bulk_loader_progress_file_handle', $file_handle);
  1062. }
  1063. if ($record_added) {
  1064. fwrite($file_handle, '.');
  1065. }
  1066. if ($line_complete) {
  1067. fwrite($file_handle, "\n");
  1068. }
  1069. // close the file if finished
  1070. if ($close) {
  1071. fclose($file_handle);
  1072. variable_set('tripal_bulk_loader_progress_file_handle', NULL);
  1073. }
  1074. }
  1075. /**
  1076. * Used to throw a hopefully human-readable error.
  1077. *
  1078. * @ingroup tripal_bulk_loader
  1079. */
  1080. function tripal_bulk_loader_throw_error($msg, $args, $severity) {
  1081. $options = ['print' => TRUE];
  1082. if ($severity == TRIPAL_NOTICE OR $severity == TRIPAL_INFO OR $severity == TRIPAL_DEBUG) {
  1083. unset($options['print']);
  1084. }
  1085. tripal_report_error(
  1086. 'tripal_bulk',
  1087. $severity,
  1088. $msg,
  1089. $args,
  1090. $options
  1091. );
  1092. }
  1093. /**
  1094. * Finishes the loading job by setting variables and exiting.
  1095. *
  1096. * @ingroup tripal_bulk_loader
  1097. */
  1098. function tripal_bulk_loader_finish_loading($nid, $loaded_without_errors) {
  1099. // set the status of the job (in the node not the tripal jobs)
  1100. if ($loaded_without_errors) {
  1101. $status = 'Loading Completed Successfully';
  1102. }
  1103. else {
  1104. $status = 'Errors Encountered';
  1105. }
  1106. db_update('tripal_bulk_loader')
  1107. ->fields(['job_status' => $status])
  1108. ->condition('nid', $nid)
  1109. ->execute();
  1110. if (!$loaded_without_errors) {
  1111. drush_set_error('BULK_LOAD_FAILED', 'Execution aborted due to errors.');
  1112. exit();
  1113. }
  1114. }