Tripal Plant PopGen Submit
form_utils.inc File Reference

Go to the source code of this file.

Functions

 tpps_dynamic_list (array &$form, array &$form_state, $id, array $repeat, array $options=array())
 
 tpps_form_state_info (array &$new, array &$old)
 
 tpps_get_ajax_number (array &$state, array $parents, $up, $down, $default=0, $minimum=0, array $options=array())
 
 tpps_get_ajax_value (array &$state, array $parents, $default=NULL, $file_name="")
 
 tpps_pre_validate ($accession, $fid, $org_num, $job=NULL)
 
 tpps_pre_validate_init ($accession=NULL)
 
 tpps_pre_validate_status ($accession=NULL, $jid=NULL)
 
 tpps_preserve_valid_file (array &$form_state, $fid, $org_num=NULL, $prefix=NULL)
 

Detailed Description

Defines useful functions to be used with the TPPS form.

Definition in file form_utils.inc.

Function Documentation

◆ tpps_dynamic_list()

tpps_dynamic_list ( array &  $form,
array &  $form_state,
  $id,
array  $repeat,
array  $options = array() 
)

Creates a dynamic list fieldset complete with add/remove buttons and ajax.

This function accepts a form object, form state object, an id, and a field to repeat, and creates a fieldset with buttons to add/remove items from the list. This function also supports a variety of additional options, which can be specified in the $options array. The list will be inserted at $form[$id], unless parents are specified in the options, in which case the list will be inserted at $form[...$parents][$id].

Parameters
array$formThe form array that the new list will be generated for.
array$form_stateThe form state array of the provided form.
string$idThe id of the dynamic list.
array$repeatThe field to repeat.
array$optionsAdditional options.

Definition at line 29 of file form_utils.inc.

29  {
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 }
tpps_get_ajax_number(array &$state, array $parents, $up, $down, $default=0, $minimum=0, array $options=array())
Definition: form_utils.inc:157

◆ tpps_form_state_info()

tpps_form_state_info ( array &  $new,
array &  $old 
)

Migrates necessary information from the old form state to the new one.

This function is usually only called from tpps_main().

Parameters
array$newThe new form state to be populated.
array$oldThe old form state with the old information.

Definition at line 290 of file form_utils.inc.

290  {
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 }

◆ tpps_get_ajax_number()

tpps_get_ajax_number ( array &  $state,
array  $parents,
  $up,
  $down,
  $default = 0,
  $minimum = 0,
array  $options = array() 
)

Retrieves the value of the number of a tpps_dynamic_list fieldset.

This function first checks the values of the form state, then the saved_values, and finally returns the default if it cannot find the number. This function also accepts an optional $options array, which contains alternative increment values, or functions which return a new number. This can be useful for adding buttons to a dynamic list such as "Add 5 of x".

Parameters
array$stateThe state of the form.
array$parentsThe parents leading to the list number.
string$upThe #name of the button to increase the list number.
string$downThe #name of the button to decrease the list number.
int$defaultThe default number if the number does not exist.
int$minimumThe minimum number we are allowed to reach.
array$optionsOptional additional increment values.
Returns
int The ajax number of the dynamic list, or the default number.

Definition at line 157 of file form_utils.inc.

157  {
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 }

◆ tpps_get_ajax_value()

tpps_get_ajax_value ( array &  $state,
array  $parents,
  $default = NULL,
  $file_name = "" 
)

Retrieves the value of a field that may have been altered through ajax.

This function first checks the 'complete form' of the form state, then the saved_values, and finally returns the default if it cannot find the value. If the value we are trying to reach is part of a TPPS managed_file, then we can also pass the file name in order to find saved_values such as 'file-columns', or 'file-no-header'.

Parameters
array$stateThe state of the form.
array$parentsThe parents leading to the list number.
mixed$defaultThe default value to return.
string$file_nameOptional - the name of the file.
Returns
mixed The value of the specified field, or the default value.

Definition at line 236 of file form_utils.inc.

236  {
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 }

◆ tpps_pre_validate()

tpps_pre_validate (   $accession,
  $fid,
  $org_num,
  $job = NULL 
)

Executes a TPPS pre-validation job.

Parameters
string$accessionThe accession of the submission being pre-validated.
int$fidThe id of the file to be pre-validated.
int$org_numThe organism number that this file is associated with.
mixed$jobThe TripalJob object of the current job.

Definition at line 451 of file form_utils.inc.

451  {
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_update_submission(array $state, array $options=array())
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_get_location($location)
Definition: file_utils.inc:640
const TPPS_PAGE_3
Definition: tpps.module:14

◆ tpps_pre_validate_init()

tpps_pre_validate_init (   $accession = NULL)

Initializes TPPS VCF file pre-validation jobs.

This function also requires that the body of the pre-validation request contains the file ids of all of the VCF files that need to be pre-validated.

Parameters
string$accessionThe accession of the submission to pre-validate.

Definition at line 349 of file form_utils.inc.

349  {
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 }
tpps_update_submission(array $state, array $options=array())
tpps_load_submission($accession, $state=TRUE)
Definition: submissions.inc:27

◆ tpps_pre_validate_status()

tpps_pre_validate_status (   $accession = NULL,
  $jid = NULL 
)

Check the status of a TPPS pre-validation job.

Parameters
string$accessionThe accession of the submission being pre-validated.
int$jidThe id of the pre-validation job.

Definition at line 424 of file form_utils.inc.

424  {
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 }
tpps_update_submission(array $state, array $options=array())
tpps_load_submission($accession, $state=TRUE)
Definition: submissions.inc:27

◆ tpps_preserve_valid_file()

tpps_preserve_valid_file ( array &  $form_state,
  $fid,
  $org_num = NULL,
  $prefix = NULL 
)

If there have been no form errors, then the file is valid, so preserve it.

Also adds the standardized name and fid to the submission state file_info.

Parameters
array$form_stateThe form state being validated.
int$fidThe Drupal file ID.
mixed$org_numThe species number to get the species name from the form state array.
mixed$prefixThe standardized file name prefix.

Definition at line 328 of file form_utils.inc.

328  {
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 }
const TPPS_PAGE_1
Definition: tpps.module:12
const TPPS_PAGE_3
Definition: tpps.module:14