Tripal Plant PopGen Submit
form_utils.inc
Go to the documentation of this file.
1 <?php
2 
29 function tpps_dynamic_list(array &$form, array &$form_state, $id, array $repeat, array $options = array()) {
30  $label = $options['label'] ?? $id;
31  $parents = $options['parents'] ?? array();
32  $number_parents = $parents;
33  array_push($number_parents, $id, 'number');
34  $up = $options['up'] ?? "Add $label";
35  $down = $options['down'] ?? "Remove $label";
36  $name_suffix = $options['name_suffix'] ?? "";
37  $default = $options['default'] ?? 0;
38  $minimum = $options['minimum'] ?? $default;
39  $fieldset_title = $options['title'] ?? "$label information:";
40  $button_callback = $options['callback'] ?? "tpps_{$id}_callback";
41  $list_wrapper = $options['wrapper'] ?? "$id-wrapper";
42  $sub_keys = $options['substitute_keys'] ?? array();
43  $sub_fields = $options['substitute_fields'] ?? array();
44  $replace_pattern = $options['replacement_pattern'] ?? '/!num/';
45  $alt_buttons = $options['alternative_buttons'] ?? array();
46  $button_weights = $options['button_weights'] ?? array();
47 
48  $element = array(
49  '#type' => 'fieldset',
50  '#tree' => TRUE,
51  '#title' => "<div class=\"fieldset-title\">$fieldset_title</div>",
52  '#collapsible' => $options['collapsible'] ?? TRUE,
53  '#prefix' => "<div id=\"$list_wrapper\">",
54  '#suffix' => '</div>',
55  'add' => array(
56  '#type' => 'button',
57  '#button_type' => 'button',
58  '#value' => $up,
59  '#name' => $up . $name_suffix,
60  '#ajax' => array(
61  'wrapper' => $list_wrapper,
62  'callback' => $button_callback,
63  ),
64  '#weight' => $button_weights[$up] ?? NULL,
65  ),
66  'remove' => array(
67  '#type' => 'button',
68  '#button_type' => 'button',
69  '#value' => $down,
70  '#name' => $down . $name_suffix,
71  '#ajax' => array(
72  'wrapper' => $list_wrapper,
73  'callback' => $button_callback,
74  ),
75  '#weight' => $button_weights[$down] ?? NULL,
76  ),
77  );
78 
79  $number_options = array();
80  foreach ($alt_buttons as $button => $inc_value) {
81  $element[$button] = array(
82  '#type' => 'button',
83  '#button_type' => 'button',
84  '#value' => $button,
85  '#name' => $button . $name_suffix,
86  '#ajax' => array(
87  'wrapper' => $list_wrapper,
88  'callback' => $button_callback,
89  ),
90  '#weight' => $button_weights[$button] ?? NULL,
91  );
92  $number_options[$button . $name_suffix] = $inc_value;
93  }
94 
95  $number = tpps_get_ajax_number($form_state, $number_parents, $up . $name_suffix, $down . $name_suffix, $default, $minimum, $number_options);
96 
97  $element['number'] = array(
98  '#type' => 'hidden',
99  '#value' => $number,
100  );
101 
102  for ($i = 1; $i <= $number; $i++) {
103  $instance = $repeat;
104  foreach ($sub_fields as $field) {
105  if (!is_array($field)) {
106  $instance[$field] = preg_replace($replace_pattern, $i, $repeat[$field]);
107  }
108  else {
109  $new_value = preg_replace($replace_pattern, $i, drupal_array_get_nested_value($repeat, $field));
110  drupal_array_set_nested_value($instance, $field, $new_value);
111  }
112  }
113  foreach ($sub_keys as $key) {
114  $value = drupal_array_get_nested_value($instance, $key);
115  drupal_array_set_nested_value($instance, $key, NULL);
116  $new_key = array();
117  foreach ($key as $key_item) {
118  $new_key[] = preg_replace($replace_pattern, $i, $key_item);
119  }
120  drupal_array_set_nested_value($instance, $new_key, $value);
121  }
122  $element[$i] = $instance;
123  }
124 
125  $element_parents = $parents;
126  array_push($element_parents, $id);
127  drupal_array_set_nested_value($form, $element_parents, $element);
128 }
129 
157 function tpps_get_ajax_number(array &$state, array $parents, $up, $down, $default = 0, $minimum = 0, array $options = array()) {
158  // Get page number.
159  $page = $state['stage'] ?? '';
160 
161  // Check form_state values, update if necessary.
162  $value_parents = $parents;
163  // If the triggering element is an upload/remove file button, then the
164  // form_state['values'] array will not be loaded correctly, so we will need
165  // to use the 'complete form' array instead.
166  $button_name = $state['triggering_element']['#name'] ?? '';
167  if (preg_match('/^.*_(upload|remove)_button$/', $button_name)) {
168  array_unshift($value_parents, 'complete form');
169  $val = drupal_array_get_nested_value($state, $value_parents);
170  if (isset($val['#type']) and $val['#type'] == 'hidden') {
171  array_push($value_parents, '#value');
172  }
173  }
174  else {
175  array_unshift($value_parents, 'values');
176  }
177  $val = drupal_array_get_nested_value($state, $value_parents);
178  if (isset($val) and array_key_exists($button_name, $options)) {
179  $increment = $options[$button_name];
180  $new_val = $val;
181  if (is_int($increment)) {
182  $new_val = $val + $increment;
183  if ($new_val < $minimum) {
184  $new_val = $minimum;
185  }
186  }
187  if (is_string($increment) and function_exists($increment)) {
188  $new_val = $increment($button_name, $val);
189  }
190  drupal_array_set_nested_value($state, $value_parents, $new_val);
191  }
192  elseif (isset($val) and $button_name == $up) {
193  drupal_array_set_nested_value($state, $value_parents, $val + 1);
194  }
195  elseif (isset($val) and $button_name == $down and $val > $minimum) {
196  drupal_array_set_nested_value($state, $value_parents, $val - 1);
197  }
198  $val = drupal_array_get_nested_value($state, $value_parents);
199  if (isset($val)) {
200  return $val;
201  }
202 
203  // Check saved values.
204  $saved_value_parents = $parents;
205  array_unshift($saved_value_parents, 'saved_values', $page);
206  $saved_val = drupal_array_get_nested_value($state, $saved_value_parents);
207  if (isset($saved_val)) {
208  return $saved_val;
209  }
210 
211  // Found nothing, return default.
212  return $default;
213 }
214 
236 function tpps_get_ajax_value(array &$state, array $parents, $default = NULL, $file_name = "") {
237  $page = $state['stage'];
238  $value_parents = $parents;
239  array_unshift($value_parents, 'values');
240  $element = drupal_array_get_nested_value($state, $value_parents);
241  if (isset($element['#type']) and $element['#type'] != 'fieldset') {
242  array_push($value_parents, '#value');
243  }
244  $val = drupal_array_get_nested_value($state, $value_parents);
245  if (isset($val)) {
246  return $val;
247  }
248 
249  $complete_parents = $parents;
250  array_unshift($complete_parents, 'complete form');
251  $element = drupal_array_get_nested_value($state, $complete_parents);
252  if (isset($element['#type']) and $element['#type'] != 'fieldset') {
253  array_push($complete_parents, '#value');
254  }
255  $val = drupal_array_get_nested_value($state, $complete_parents);
256  if (isset($val)) {
257  return $val;
258  }
259 
260  $saved_value_parents = $parents;
261  if (!empty($file_name)) {
262  $saved_value_parents = array();
263  $last = '';
264  foreach ($parents as $item) {
265  if ($last == $file_name) {
266  $item = "$file_name-$item";
267  }
268  $last = $item;
269  if ($item == $file_name) {
270  continue;
271  }
272  $saved_value_parents[] = $item;
273  }
274  }
275  array_unshift($saved_value_parents, 'saved_values', $page);
276  $saved_val = drupal_array_get_nested_value($state, $saved_value_parents);
277  return $saved_val ?? $default;
278 }
279 
290 function tpps_form_state_info(array &$new, array &$old) {
291  $new['saved_values'] = $old['saved_values'];
292  $new['stage'] = $old['stage'];
293  $new['accession'] = $old['accession'];
294  $new['dbxref_id'] = $old['dbxref_id'];
295  $new['stats'] = $old['stats'] ?? NULL;
296  $new['ids'] = $old['ids'] ?? NULL;
297  $new['tpps_type'] = $old['tpps_type'] ?? NULL;
298  $new['file_info'] = $old['file_info'] ?? NULL;
299  $new['status'] = $old['status'] ?? NULL;
300  $new['updated'] = $old['updated'] ?? time();
301  $new['created'] = $old['created'] ?? NULL;
302  $new['approved'] = $old['approved'] ?? NULL;
303  $new['completed'] = $old['completed'] ?? NULL;
304  $new['loaded'] = $old['loaded'] ?? NULL;
305  $new['submitting_uid'] = $old['submitting_uid'] ?? NULL;
306  $new['job_id'] = $old['job_id'] ?? NULL;
307  $new['revised_files'] = $old['revised_files'] ?? NULL;
308  $new['admin_comments'] = $old['admin_comments'] ?? NULL;
309  $new['alternative_accessions'] = $old['alternative_accessions'] ?? NULL;
310  $new['data'] = $old['data'] ?? NULL;
311  $new['phenotypes_edit'] = $old['phenotypes_edit'] ?? NULL;
312 }
313 
328 function tpps_preserve_valid_file(array &$form_state, $fid, $org_num = NULL, $prefix = NULL) {
329  if (!form_get_errors()) {
330  $file = file_load($fid);
331  file_usage_add($file, 'tpps', 'tpps_project', substr($form_state['accession'], 4));
332 
333  if (!empty($org_num) and !empty($prefix)) {
334  $species = implode('_', explode(' ', $form_state['saved_values'][TPPS_PAGE_1]['organism'][$org_num]['name']));
335  $form_state['file_info'][TPPS_PAGE_3][$file->fid] = "{$prefix}_{$species}";
336  }
337  }
338 }
339 
349 function tpps_pre_validate_init($accession = NULL) {
350  $state = tpps_load_submission($accession);
351  if (empty($accession) or empty($state)) {
352  drupal_json_output("Submission could not be loaded from accession");
353  return;
354  }
355  $params = drupal_get_query_parameters(NULL, array());
356  $vcfs = $params['vcfs'] ?? NULL;
357  if (!is_array($vcfs) or empty($vcfs)) {
358  drupal_json_output("No VCF file ids were provided");
359  return;
360  }
361 
362  global $user;
363  $state['vcf_replace'] = array();
364  foreach ($vcfs as $org_num => $fid) {
365  if (!file_load($fid)) {
366  if (!is_string($fid)) {
367  drupal_json_output("Could not load one or more VCFs from file ID");
368  return;
369  }
370  elseif (!file_exists($fid)) {
371  drupal_json_output("One or more VCF local paths was invalid");
372  return;
373  }
374  else {
375  $existing_files = file_load_multiple(FALSE, array('uri' => $fid));
376  if (!empty($existing_files)) {
377  $file = current($existing_files);
378  }
379  else {
380  $file = new stdClass();
381  $file->fid = NULL;
382  $file->uri = $fid;
383  $file->filename = drupal_basename($fid);
384  $file->filemime = file_get_mimetype($file->uri);
385  $file->uid = $user->uid;
386  $file->status = 0;
387  $file = file_save($file);
388  }
389 
390  $vcfs[$org_num] = $file->fid;
391  $state['vcf_replace'][$org_num] = $file->fid;
392  }
393  }
394  }
395  if (empty($state['vcf_replace'])) {
396  unset($state['vcf_replace']);
397  }
398 
399  $state['vcf_val_errors'] = array();
400  $state['vcf_validated'] = FALSE;
401  tpps_update_submission($state);
402 
403  $jobs = array();
404  foreach ($vcfs as $org_num => $fid) {
405  $includes = array();
406  $includes[] = module_load_include('inc', 'tpps', 'includes/form_utils');
407  $includes[] = module_load_include('inc', 'tpps', 'includes/file_parsing');
408  $args = array($accession, $fid, $org_num);
409  $jobs[] = tripal_add_job("{$accession} Pre-validate VCF {$fid}", 'tpps', 'tpps_pre_validate', $args, $user->uid, 10, $includes, TRUE);
410  }
411  drupal_get_messages('status', TRUE);
412 
413  drupal_json_output($jobs);
414 }
415 
424 function tpps_pre_validate_status($accession = NULL, $jid = NULL) {
425  $job = tripal_get_job($jid);
426 
427  if ($job->status == 'Completed') {
428  $state = tpps_load_submission($accession);
429  $job->val_errors = $state['vcf_val_errors'] ?? array();
430  if (empty($job->val_errors)) {
431  $state['vcf_validated'] = TRUE;
432  tpps_update_submission($state);
433  }
434  }
435 
436  drupal_json_output($job);
437 }
438 
451 function tpps_pre_validate($accession, $fid, $org_num, $job = NULL) {
452  if (empty($job)) {
453  return;
454  }
455  $job->logMessage("[INFO] TGDR Accession: $accession");
456  $job->logMessage("[INFO] VCF File ID: $fid");
457  $job->logMessage("[INFO] Organism Number: $org_num");
458  $vcf_file = file_load($fid);
459  if (!$vcf_file) {
460  $job->logMessage("[ERROR] VCF File failed to load", array(), TRIPAL_ERROR);
461  return;
462  }
463  $job->logMessage("[INFO] VCF File Location: {$vcf_file->uri}");
464 
465  $state = tpps_load_submission($accession);
466  if (empty($state['saved_values'][TPPS_PAGE_3]['tree-accession']['check'])) {
467  $species_index = 'species-1';
468  }
469  else {
470  $species_index = "species-$org_num";
471  }
472  $tree_accession_file = $state['saved_values'][TPPS_PAGE_3]['tree-accession'][$species_index]['file'];
473  $id_col_accession_name = $state['saved_values'][TPPS_PAGE_3]['tree-accession'][$species_index]['file-groups']['Tree Id']['1'];
474  $accession_ids = tpps_parse_file_column($tree_accession_file, $id_col_accession_name);
475 
476  $job->logMessage("[INFO] Extracting VCF archive...");
477  $location = tpps_get_location($vcf_file->uri);
478  $job->logMessage("[INFO] Opening $location...");
479  $vcf_content = gzopen($location, 'r');
480  $stocks = array();
481  while (($vcf_line = gzgets($vcf_content)) !== FALSE) {
482  if (preg_match('/#CHROM/', $vcf_line)) {
483  $vcf_line = explode("\t", $vcf_line);
484  for ($j = 9; $j < count($vcf_line); $j++) {
485  $stocks[] = trim($vcf_line[$j]);
486  }
487  break;
488  }
489  }
490 
491  $state_errors = $state['vcf_val_errors'] ?? array();
492  if (count($stocks) == 0) {
493  $message = "unable to parse Plant Identifiers. The format of your VCF file must be invalid";
494  $job->logMessage("[ERROR] $message", array(), TRIPAL_ERROR);
495  $state_errors[] = "Genotype VCF File: $message";
496  }
497  else {
498  $missing_plants = array();
499  foreach ($stocks as $stock_id) {
500  if (array_search($stock_id, $accession_ids) === FALSE) {
501  $missing_plants[] = $stock_id;
502  }
503  }
504  if (count($missing_plants) > 0) {
505  $missing_plants = implode(', ', $missing_plants);
506  $message = "We found Plant Identifiers in your VCF file that were not present in your accession file. Please either add these plants to your accession file or remove them from your VCF file. The missing plants are: {$missing_plants}.";
507  $job->logMessage("[ERROR] $message", array(), TRIPAL_ERROR);
508  $state_errors[] = "Genotype VCF File: $message";
509  }
510  }
511 
512  if (empty($state_errors)) {
513  $job->logMessage("[INFO] VCF Validated successfully - no errors!");
514  }
515  else {
516  $state['vcf_val_errors'] = $state_errors;
517  tpps_update_submission($state);
518  }
519 }
tpps_pre_validate_init($accession=NULL)
Definition: form_utils.inc:349
const TPPS_PAGE_1
Definition: tpps.module:12
tpps_get_ajax_value(array &$state, array $parents, $default=NULL, $file_name="")
Definition: form_utils.inc:236
tpps_dynamic_list(array &$form, array &$form_state, $id, array $repeat, array $options=array())
Definition: form_utils.inc:29
tpps_update_submission(array $state, array $options=array())
tpps_form_state_info(array &$new, array &$old)
Definition: form_utils.inc:290
tpps_parse_file_column($fid, $column, $no_header=FALSE)
Definition: file_utils.inc:334
tpps_load_submission($accession, $state=TRUE)
Definition: submissions.inc:27
tpps_preserve_valid_file(array &$form_state, $fid, $org_num=NULL, $prefix=NULL)
Definition: form_utils.inc:328
tpps_get_location($location)
Definition: file_utils.inc:640
tpps_pre_validate($accession, $fid, $org_num, $job=NULL)
Definition: form_utils.inc:451
tpps_pre_validate_status($accession=NULL, $jid=NULL)
Definition: form_utils.inc:424
const TPPS_PAGE_3
Definition: tpps.module:14
tpps_get_ajax_number(array &$state, array $parents, $up, $down, $default=0, $minimum=0, array $options=array())
Definition: form_utils.inc:157