From 26c5898c6170a58cd618dfe868c7a1bd34e26023 Mon Sep 17 00:00:00 2001 From: Malladi Date: Mon, 24 Apr 2023 21:36:27 -0500 Subject: [PATCH 01/74] Issue 1414 local source data field for Analysis --- .../ChadoLocalSourceDataFormatterDefault.php | 64 +++++++++++ .../FieldType/ChadoLocalSourceDataDefault.php | 105 ++++++++++++++++++ .../ChadoLocalSourceDataWidgetDefault.php | 76 +++++++++++++ 3 files changed, 245 insertions(+) create mode 100755 tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php create mode 100755 tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php create mode 100755 tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php diff --git a/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php b/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php new file mode 100755 index 000000000..d4e90051b --- /dev/null +++ b/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php @@ -0,0 +1,64 @@ + $item) { + $content = "
"; + $prog_vers_val = $item->get( 'programversion' )->getString() ; + if ( !empty( $prog_vers_val ) ) { + $content .= "
Software version
: " . $prog_vers_val . "
"; + } + $sourcename_val = $item->get( 'sourcename' )->getString() ; + if ( !empty( $sourcename_val ) ) { + $content .= "
Source Name
: " . $sourcename_val . "
"; + } + $sourceversion_val = $item->get( 'sourceversion' )->getString() ; + if ( !empty( $sourceversion_val ) ) { + $content .= "
Source Version
: " . $sourceversion_val . "
"; + } + $sourceuri_val = $item->get( 'sourceuri' )->getString() ; + /* + if (preg_match('/^https?:/i', $sourceuri_val ) ) { + $sourceuri_val = Link::fromTextAndUrl($sourceuri_val, $sourceuri_val); + } + */ + if ( !empty( $sourceuri_val ) ) { + $content .= "
Source URI
: " . $sourceuri_val . "
"; + } + $content .= "
"; + } + $elements[$delta] = [ + '#type' => 'markup', + '#markup' => $content, + ]; + + return $elements; + } +} diff --git a/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php b/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php new file mode 100755 index 000000000..edf9e9c15 --- /dev/null +++ b/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php @@ -0,0 +1,105 @@ +getTargetEntityTypeId(); + + // Get the property terms by using the Chado table columns they map to. + $storage = \Drupal::entityTypeManager()->getStorage('chado_term_mapping'); + $mapping = $storage->load('core_mapping'); + + $record_id_term = $mapping->getColumnTermId('analysis', 'analysis_id'); + + $prog_vers_term = $mapping->getColumnTermId('analysis', 'programversion'); + $src_uri_term = $mapping->getColumnTermId('analysis', 'sourceuri'); + $src_name_term = $mapping->getColumnTermId('analysis', 'sourcename'); + $src_vers_term = $mapping->getColumnTermId('analysis', 'sourceversion'); + + // Get property terms using Chado table columns they map to. Return the properties for this field. + $properties = []; + + $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'record_id', $record_id_term, [ + 'action' => 'store_id', + 'drupal_store' => TRUE, + 'chado_table' => 'analysis', + 'chado_column' => 'analysis_id', + ]); + $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'programversion', $prog_vers_term, 100, [ + 'action' => 'store', + 'chado_table' => 'analysis', + 'chado_column' => 'programversion', + ]); + $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'sourceuri', $src_uri_term, 100, [ + 'action' => 'store', + 'chado_table' => 'analysis', + 'chado_column' => 'sourceuri', + ]); + $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'sourcename', $src_name_term, 200, [ + 'action' => 'store', + 'chado_table' => 'analysis', + 'chado_column' => 'sourcename', + 'delete_if_empty' => TRUE, + 'empty_value' => '', + ]); + $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'sourceversion', $src_vers_term, 100, [ + 'action' => 'store', + 'chado_table' => 'analysis', + 'chado_column' => 'sourceversion', + ]); + + return($properties); + } + +} diff --git a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php new file mode 100755 index 000000000..b8c8341ec --- /dev/null +++ b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php @@ -0,0 +1,76 @@ +getValue(); + + $elements = []; + $elements['record_id'] = [ + '#type' => 'value', + '#default_value' => $item_vals['record_id'] ?? 0, + ]; + + $elements['programversion'] = [ + '#title' => "Software version", + '#type' => 'textfield', + '#default_value' => $item_vals['programversion'] ?? '', + ]; + $elements['sourceuri'] = [ + '#title' => "Local Source URI", + '#type' => 'textfield', + '#default_value' => $item_vals['sourceuri'] ?? '', + ]; + $elements['sourcename'] = [ + '#title' => "Local Source Name", + '#type' => 'textfield', + '#default_value' => $item_vals['sourcename'] ?? '', + ]; + $elements['sourceversion'] = [ + '#type' => 'textfield', + '#default_value' => $item_vals['sourceversion'] ?? '', + '#title' => 'Local Source Version', + ]; + + return $elements; + } + + + /** + * {@inheritDoc} + */ + public function massageFormValues(array $values, array $form, FormStateInterface $form_state) { + + // Remove any empty values that aren't mapped to a record id. + foreach ($values as $val_key => $value) { + $values[$val_key]['programversion'] = $value['programversion']; + $values[$val_key]['sourceuri'] = $value['sourceuri']; + $values[$val_key]['sourcename'] = $value['sourcename']; + $values[$val_key]['sourceversion'] = $value['sourceversion']; + } + return $values; + } + +} \ No newline at end of file From 9148d9b22a181046f105c4daa84598322187405d Mon Sep 17 00:00:00 2001 From: Malladi Date: Thu, 4 May 2023 11:13:17 -0500 Subject: [PATCH 02/74] Issue 1414 local source data field for Analysis - removed programversion --- .../ChadoLocalSourceDataFormatterDefault.php | 60 +++++++++++ .../FieldType/ChadoLocalSourceDataDefault.php | 100 ++++++++++++++++++ .../ChadoLocalSourceDataWidgetDefault.php | 70 ++++++++++++ 3 files changed, 230 insertions(+) create mode 100755 tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php create mode 100755 tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php create mode 100755 tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php diff --git a/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php b/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php new file mode 100755 index 000000000..85d4782b9 --- /dev/null +++ b/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php @@ -0,0 +1,60 @@ + $item) { + $content = "
"; + $sourcename_val = $item->get( 'sourcename' )->getString() ; + if ( !empty( $sourcename_val ) ) { + $content .= "
Source Name
: " . $sourcename_val . "
"; + } + $sourceversion_val = $item->get( 'sourceversion' )->getString() ; + if ( !empty( $sourceversion_val ) ) { + $content .= "
Source Version
: " . $sourceversion_val . "
"; + } + $sourceuri_val = $item->get( 'sourceuri' )->getString() ; + /* + if (preg_match('/^https?:/i', $sourceuri_val ) ) { + $sourceuri_val = Link::fromTextAndUrl($sourceuri_val, $sourceuri_val); + } + */ + if ( !empty( $sourceuri_val ) ) { + $content .= "
Source URI
: " . $sourceuri_val . "
"; + } + $content .= "
"; + } + $elements[$delta] = [ + '#type' => 'markup', + '#markup' => $content, + ]; + + return $elements; + } +} diff --git a/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php b/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php new file mode 100755 index 000000000..58bbf69a7 --- /dev/null +++ b/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php @@ -0,0 +1,100 @@ +getTargetEntityTypeId(); + + // Get the property terms by using the Chado table columns they map to. + $storage = \Drupal::entityTypeManager()->getStorage('chado_term_mapping'); + $mapping = $storage->load('core_mapping'); + + $record_id_term = $mapping->getColumnTermId('analysis', 'analysis_id'); + + $prog_vers_term = $mapping->getColumnTermId('analysis', 'programversion'); + $src_uri_term = $mapping->getColumnTermId('analysis', 'sourceuri'); + $src_name_term = $mapping->getColumnTermId('analysis', 'sourcename'); + $src_vers_term = $mapping->getColumnTermId('analysis', 'sourceversion'); + + // Get property terms using Chado table columns they map to. Return the properties for this field. + $properties = []; + + $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'record_id', $record_id_term, [ + 'action' => 'store_id', + 'drupal_store' => TRUE, + 'chado_table' => 'analysis', + 'chado_column' => 'analysis_id', + ]); + $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'sourceuri', $src_uri_term, 100, [ + 'action' => 'store', + 'chado_table' => 'analysis', + 'chado_column' => 'sourceuri', + ]); + $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'sourcename', $src_name_term, 200, [ + 'action' => 'store', + 'chado_table' => 'analysis', + 'chado_column' => 'sourcename', + 'delete_if_empty' => TRUE, + 'empty_value' => '', + ]); + $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'sourceversion', $src_vers_term, 100, [ + 'action' => 'store', + 'chado_table' => 'analysis', + 'chado_column' => 'sourceversion', + ]); + + return($properties); + } + +} diff --git a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php new file mode 100755 index 000000000..b16dfd688 --- /dev/null +++ b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php @@ -0,0 +1,70 @@ +getValue(); + + $elements = []; + $elements['record_id'] = [ + '#type' => 'value', + '#default_value' => $item_vals['record_id'] ?? 0, + ]; + $elements['sourceuri'] = [ + '#title' => "Local Source URI", + '#type' => 'textfield', + '#default_value' => $item_vals['sourceuri'] ?? '', + ]; + $elements['sourcename'] = [ + '#title' => "Local Source Name", + '#type' => 'textfield', + '#default_value' => $item_vals['sourcename'] ?? '', + ]; + $elements['sourceversion'] = [ + '#type' => 'textfield', + '#default_value' => $item_vals['sourceversion'] ?? '', + '#title' => 'Local Source Version', + ]; + + return $elements; + } + + + /** + * {@inheritDoc} + */ + public function massageFormValues(array $values, array $form, FormStateInterface $form_state) { + + // Remove any empty values that aren't mapped to a record id. + foreach ($values as $val_key => $value) { + $values[$val_key]['programversion'] = $value['programversion']; + $values[$val_key]['sourceuri'] = $value['sourceuri']; + $values[$val_key]['sourcename'] = $value['sourcename']; + $values[$val_key]['sourceversion'] = $value['sourceversion']; + } + return $values; + } + +} \ No newline at end of file From 698040a2c88eff5266f1641a89ef317fca809544 Mon Sep 17 00:00:00 2001 From: Malladi Date: Thu, 4 May 2023 12:46:41 -0500 Subject: [PATCH 03/74] Issue 1414 local source data fields for Analysis --- .../ChadoLocalSourceDataFormatterDefault.php | 54 ++++++++++ .../FieldType/ChadoLocalSourceDataDefault.php | 99 +++++++++++++++++++ .../ChadoLocalSourceDataWidgetDefault.php | 69 +++++++++++++ 3 files changed, 222 insertions(+) create mode 100755 tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php create mode 100755 tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php create mode 100755 tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php diff --git a/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php b/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php new file mode 100755 index 000000000..340f0c79f --- /dev/null +++ b/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php @@ -0,0 +1,54 @@ + $item) { + $content = "
"; + $sourcename_val = $item->get( 'sourcename' )->getString() ; + if ( !empty( $sourcename_val ) ) { + $content .= "
Source Name
: " . $sourcename_val . "
"; + } + $sourceversion_val = $item->get( 'sourceversion' )->getString() ; + if ( !empty( $sourceversion_val ) ) { + $content .= "
Source Version
: " . $sourceversion_val . "
"; + } + $sourceuri_val = $item->get( 'sourceuri' )->getString() ; + if ( !empty( $sourceuri_val ) ) { + $content .= "
Source URI
: " . $sourceuri_val . "
"; + } + $content .= "
"; + } + $elements[$delta] = [ + '#type' => 'markup', + '#markup' => $content, + ]; + + return $elements; + } +} diff --git a/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php b/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php new file mode 100755 index 000000000..ebfecddcf --- /dev/null +++ b/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php @@ -0,0 +1,99 @@ +getTargetEntityTypeId(); + + // Get the property terms by using the Chado table columns they map to. + $storage = \Drupal::entityTypeManager()->getStorage('chado_term_mapping'); + $mapping = $storage->load('core_mapping'); + + $record_id_term = $mapping->getColumnTermId('analysis', 'analysis_id'); + + $src_uri_term = $mapping->getColumnTermId('analysis', 'sourceuri'); + $src_name_term = $mapping->getColumnTermId('analysis', 'sourcename'); + $src_vers_term = $mapping->getColumnTermId('analysis', 'sourceversion'); + + // Get property terms using Chado table columns they map to. Return the properties for this field. + $properties = []; + + $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'record_id', $record_id_term, [ + 'action' => 'store_id', + 'drupal_store' => TRUE, + 'chado_table' => 'analysis', + 'chado_column' => 'analysis_id', + ]); + $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'sourceuri', $src_uri_term, 100, [ + 'action' => 'store', + 'chado_table' => 'analysis', + 'chado_column' => 'sourceuri', + ]); + $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'sourcename', $src_name_term, 200, [ + 'action' => 'store', + 'chado_table' => 'analysis', + 'chado_column' => 'sourcename', + 'delete_if_empty' => TRUE, + 'empty_value' => '', + ]); + $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'sourceversion', $src_vers_term, 100, [ + 'action' => 'store', + 'chado_table' => 'analysis', + 'chado_column' => 'sourceversion', + ]); + + return($properties); + } + +} diff --git a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php new file mode 100755 index 000000000..7217ad62a --- /dev/null +++ b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php @@ -0,0 +1,69 @@ +getValue(); + + $elements = []; + $elements['record_id'] = [ + '#type' => 'value', + '#default_value' => $item_vals['record_id'] ?? 0, + ]; + $elements['sourceuri'] = [ + '#title' => "Local Source URI", + '#type' => 'textfield', + '#default_value' => $item_vals['sourceuri'] ?? '', + ]; + $elements['sourcename'] = [ + '#title' => "Local Source Name", + '#type' => 'textfield', + '#default_value' => $item_vals['sourcename'] ?? '', + ]; + $elements['sourceversion'] = [ + '#type' => 'textfield', + '#default_value' => $item_vals['sourceversion'] ?? '', + '#title' => 'Local Source Version', + ]; + + return $elements; + } + + + /** + * {@inheritDoc} + */ + public function massageFormValues(array $values, array $form, FormStateInterface $form_state) { + + // Remove any empty values that aren't mapped to a record id. + foreach ($values as $val_key => $value) { + $values[$val_key]['sourceuri'] = $value['sourceuri']; + $values[$val_key]['sourcename'] = $value['sourcename']; + $values[$val_key]['sourceversion'] = $value['sourceversion']; + } + return $values; + } + +} \ No newline at end of file From 79f27155bde2de950ac5068a9b396ec8a9005469 Mon Sep 17 00:00:00 2001 From: dsenalik Date: Thu, 4 May 2023 15:12:14 -0500 Subject: [PATCH 04/74] cardinality, formatting, url clickable --- .../ChadoLocalSourceDataFormatterDefault.php | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php b/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php index 340f0c79f..f67febc3d 100755 --- a/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php @@ -3,6 +3,8 @@ namespace Drupal\tripal_chado\Plugin\Field\FieldFormatter; use Drupal\Core\Field\FieldItemListInterface; +use Drupal\Core\Link; +use Drupal\Core\Url; use Drupal\tripal_chado\TripalField\ChadoFormatterBase; /** @@ -11,7 +13,7 @@ * @FieldFormatter( * id = "chado_local_source_data_formatter_default", * label = @Translation("Chado Local Source Data Formatter"), - * description = @Translation("Analysis local source data formatter default"), + * description = @Translation("Analysis source name, version, and uri formatter"), * field_types = { * "chado_local_source_data_default" * } @@ -30,17 +32,21 @@ public function viewElements(FieldItemListInterface $items, $langcode) { foreach($items as $delta => $item) { $content = "
"; - $sourcename_val = $item->get( 'sourcename' )->getString() ; + $sourcename_val = $item->get('sourcename')->getString() ; if ( !empty( $sourcename_val ) ) { - $content .= "
Source Name
: " . $sourcename_val . "
"; + $content .= "
Source Name
" . $sourcename_val . "
"; } - $sourceversion_val = $item->get( 'sourceversion' )->getString() ; + $sourceversion_val = $item->get('sourceversion')->getString() ; if ( !empty( $sourceversion_val ) ) { - $content .= "
Source Version
: " . $sourceversion_val . "
"; + $content .= "
Source Version
" . $sourceversion_val . "
"; } - $sourceuri_val = $item->get( 'sourceuri' )->getString() ; + $sourceuri_val = $item->get('sourceuri')->getString() ; if ( !empty( $sourceuri_val ) ) { - $content .= "
Source URI
: " . $sourceuri_val . "
"; + $url = $sourceuri_val; + if (preg_match('|://|', $sourceuri_val ) { + $url = Link::fromTextAndUrl($sourceuri_val, Url::fromUri($sourceuri_val, []))->toString(); + } + $content .= "
Source URI
" . $url . "
"; } $content .= "
"; } @@ -48,7 +54,8 @@ public function viewElements(FieldItemListInterface $items, $langcode) { '#type' => 'markup', '#markup' => $content, ]; - + return $elements; } + } From 778a9a90b28b1baa04c657ab6ded48576d652c73 Mon Sep 17 00:00:00 2001 From: dsenalik Date: Thu, 4 May 2023 16:44:46 -0500 Subject: [PATCH 05/74] commit before fixing my mess --- .../FieldType/ChadoLocalSourceDataDefault.php | 18 ++++++++++-------- .../ChadoLocalSourceDataWidgetDefault.php | 10 +++++----- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php b/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php index ebfecddcf..63507d434 100755 --- a/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php @@ -2,6 +2,7 @@ namespace Drupal\tripal_chado\Plugin\Field\FieldType; +use Drupal\Core\Form\FormStateInterface; use Drupal\tripal_chado\TripalField\ChadoFieldItemBase; use Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType; use Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType; @@ -11,15 +12,16 @@ * * @FieldType( * id = "chado_local_source_data_default", - * label = @Translation("Chado local analysis source data"), - * description = @Translation("The local source data used for this analysis"), + * label = @Translation("Chado Local Source Data"), + * description = @Translation("The source and version of data used for this analysis"), * default_widget = "chado_local_source_data_widget_default", - * default_formatter = "chado_local_source_data_formatter_default" + * default_formatter = "chado_local_source_data_formatter_default", + * cardinality = 1, * ) */ class ChadoLocalSourceDataDefault extends ChadoFieldItemBase { - public static $id = "chado_local_source_data_default"; + public static $id = 'chado_local_source_data_default'; /** * {@inheritdoc} @@ -39,7 +41,7 @@ public static function defaultFieldSettings() { return $settings; } - /** + /** * {@inheritdoc} */ public static function defaultStorageSettings() { @@ -65,7 +67,7 @@ public static function tripalTypes($field_definition) { $src_uri_term = $mapping->getColumnTermId('analysis', 'sourceuri'); $src_name_term = $mapping->getColumnTermId('analysis', 'sourcename'); $src_vers_term = $mapping->getColumnTermId('analysis', 'sourceversion'); - + // Get property terms using Chado table columns they map to. Return the properties for this field. $properties = []; @@ -92,8 +94,8 @@ public static function tripalTypes($field_definition) { 'chado_table' => 'analysis', 'chado_column' => 'sourceversion', ]); - - return($properties); + + return($properties); } } diff --git a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php index 7217ad62a..343f396a8 100755 --- a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php @@ -11,7 +11,7 @@ * * @FieldWidget( * id = "chado_local_source_data_widget_default", - * label = @Translation("Chado analysis local source data Widget default"), + * label = @Translation("Chado Local Source Data Widget Default"), * description = @Translation("The default chado local source data widget which allows curators to manually enter analysis source on the content edit page."), * field_types = { * "chado_local_source_data_default" @@ -56,14 +56,14 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen * {@inheritDoc} */ public function massageFormValues(array $values, array $form, FormStateInterface $form_state) { - + // Remove any empty values that aren't mapped to a record id. foreach ($values as $val_key => $value) { - $values[$val_key]['sourceuri'] = $value['sourceuri']; - $values[$val_key]['sourcename'] = $value['sourcename']; + $values[$val_key]['sourceuri'] = $value['sourceuri']; + $values[$val_key]['sourcename'] = $value['sourcename']; $values[$val_key]['sourceversion'] = $value['sourceversion']; } return $values; } -} \ No newline at end of file +} From 56964cdc12e4d6e5fb8f3f06ac15619ba9b67658 Mon Sep 17 00:00:00 2001 From: sm1005 Date: Thu, 4 May 2023 19:51:20 -0500 Subject: [PATCH 06/74] Revert "Tv4g1 issue1414 local data source field suggestions" --- .../ChadoLocalSourceDataFormatterDefault.php | 38 +++++++++---------- .../FieldType/ChadoLocalSourceDataDefault.php | 27 ++++++++----- .../ChadoLocalSourceDataWidgetDefault.php | 20 +++++++--- 3 files changed, 50 insertions(+), 35 deletions(-) diff --git a/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php b/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php index 2a12bb0d5..9798d7dd0 100755 --- a/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php @@ -3,9 +3,8 @@ namespace Drupal\tripal_chado\Plugin\Field\FieldFormatter; use Drupal\Core\Field\FieldItemListInterface; -use Drupal\Core\Link; -use Drupal\Core\Url; use Drupal\tripal_chado\TripalField\ChadoFormatterBase; +use Drupal\Core\Link; /** * Plugin implementation of default Tripal string type formatter. @@ -13,7 +12,7 @@ * @FieldFormatter( * id = "chado_local_source_data_formatter_default", * label = @Translation("Chado Local Source Data Formatter"), - * description = @Translation("Analysis source name, version, and uri formatter"), + * description = @Translation("Analysis local source data formatter default"), * field_types = { * "chado_local_source_data_default" * } @@ -32,22 +31,13 @@ public function viewElements(FieldItemListInterface $items, $langcode) { foreach($items as $delta => $item) { $content = "
"; - $sourcename_val = $item->get('sourcename')->getString() ; - if ( !empty( $sourcename_val ) ) { - $content .= "
Source Name
" . $sourcename_val . "
"; - } - $sourceversion_val = $item->get('sourceversion')->getString() ; - if ( !empty( $sourceversion_val ) ) { - $content .= "
Source Version
" . $sourceversion_val . "
"; - } - $sourceuri_val = $item->get('sourceuri')->getString() ; - if ( !empty( $sourceuri_val ) ) { - $url = $sourceuri_val; - if (preg_match('|://|', $sourceuri_val ) { - $url = Link::fromTextAndUrl($sourceuri_val, Url::fromUri($sourceuri_val, []))->toString(); - } - $content .= "
Source URI
" . $url . "
"; +<<<<<<< HEAD +======= + $prog_vers_val = $item->get( 'programversion' )->getString() ; + if ( !empty( $prog_vers_val ) ) { + $content .= "
Software version
: " . $prog_vers_val . "
"; } +>>>>>>> b73440286faed0b3cf68dec7fdff3e2bb4528450 $sourcename_val = $item->get( 'sourcename' )->getString() ; if ( !empty( $sourcename_val ) ) { $content .= "
Source Name
: " . $sourcename_val . "
"; @@ -56,14 +46,22 @@ public function viewElements(FieldItemListInterface $items, $langcode) { if ( !empty( $sourceversion_val ) ) { $content .= "
Source Version
: " . $sourceversion_val . "
"; } + $sourceuri_val = $item->get( 'sourceuri' )->getString() ; + /* + if (preg_match('/^https?:/i', $sourceuri_val ) ) { + $sourceuri_val = Link::fromTextAndUrl($sourceuri_val, $sourceuri_val); + } + */ + if ( !empty( $sourceuri_val ) ) { + $content .= "
Source URI
: " . $sourceuri_val . "
"; + } $content .= "
"; } $elements[$delta] = [ '#type' => 'markup', '#markup' => $content, ]; - + return $elements; } - } diff --git a/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php b/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php index 63507d434..2ca8f71d8 100755 --- a/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php @@ -2,7 +2,6 @@ namespace Drupal\tripal_chado\Plugin\Field\FieldType; -use Drupal\Core\Form\FormStateInterface; use Drupal\tripal_chado\TripalField\ChadoFieldItemBase; use Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType; use Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType; @@ -12,16 +11,15 @@ * * @FieldType( * id = "chado_local_source_data_default", - * label = @Translation("Chado Local Source Data"), - * description = @Translation("The source and version of data used for this analysis"), + * label = @Translation("Chado local analysis source data"), + * description = @Translation("The local source data used for this analysis"), * default_widget = "chado_local_source_data_widget_default", - * default_formatter = "chado_local_source_data_formatter_default", - * cardinality = 1, + * default_formatter = "chado_local_source_data_formatter_default" * ) */ class ChadoLocalSourceDataDefault extends ChadoFieldItemBase { - public static $id = 'chado_local_source_data_default'; + public static $id = "chado_local_source_data_default"; /** * {@inheritdoc} @@ -41,7 +39,7 @@ public static function defaultFieldSettings() { return $settings; } - /** + /** * {@inheritdoc} */ public static function defaultStorageSettings() { @@ -64,10 +62,11 @@ public static function tripalTypes($field_definition) { $record_id_term = $mapping->getColumnTermId('analysis', 'analysis_id'); + $prog_vers_term = $mapping->getColumnTermId('analysis', 'programversion'); $src_uri_term = $mapping->getColumnTermId('analysis', 'sourceuri'); $src_name_term = $mapping->getColumnTermId('analysis', 'sourcename'); $src_vers_term = $mapping->getColumnTermId('analysis', 'sourceversion'); - + // Get property terms using Chado table columns they map to. Return the properties for this field. $properties = []; @@ -77,6 +76,14 @@ public static function tripalTypes($field_definition) { 'chado_table' => 'analysis', 'chado_column' => 'analysis_id', ]); +<<<<<<< HEAD +======= + $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'programversion', $prog_vers_term, 100, [ + 'action' => 'store', + 'chado_table' => 'analysis', + 'chado_column' => 'programversion', + ]); +>>>>>>> b73440286faed0b3cf68dec7fdff3e2bb4528450 $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'sourceuri', $src_uri_term, 100, [ 'action' => 'store', 'chado_table' => 'analysis', @@ -94,8 +101,8 @@ public static function tripalTypes($field_definition) { 'chado_table' => 'analysis', 'chado_column' => 'sourceversion', ]); - - return($properties); + + return($properties); } } diff --git a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php index 343f396a8..01adf86ad 100755 --- a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php @@ -11,7 +11,7 @@ * * @FieldWidget( * id = "chado_local_source_data_widget_default", - * label = @Translation("Chado Local Source Data Widget Default"), + * label = @Translation("Chado analysis local source data Widget default"), * description = @Translation("The default chado local source data widget which allows curators to manually enter analysis source on the content edit page."), * field_types = { * "chado_local_source_data_default" @@ -32,6 +32,15 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen '#type' => 'value', '#default_value' => $item_vals['record_id'] ?? 0, ]; +<<<<<<< HEAD +======= + + $elements['programversion'] = [ + '#title' => "Software version", + '#type' => 'textfield', + '#default_value' => $item_vals['programversion'] ?? '', + ]; +>>>>>>> b73440286faed0b3cf68dec7fdff3e2bb4528450 $elements['sourceuri'] = [ '#title' => "Local Source URI", '#type' => 'textfield', @@ -56,14 +65,15 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen * {@inheritDoc} */ public function massageFormValues(array $values, array $form, FormStateInterface $form_state) { - + // Remove any empty values that aren't mapped to a record id. foreach ($values as $val_key => $value) { - $values[$val_key]['sourceuri'] = $value['sourceuri']; - $values[$val_key]['sourcename'] = $value['sourcename']; + $values[$val_key]['programversion'] = $value['programversion']; + $values[$val_key]['sourceuri'] = $value['sourceuri']; + $values[$val_key]['sourcename'] = $value['sourcename']; $values[$val_key]['sourceversion'] = $value['sourceversion']; } return $values; } -} +} \ No newline at end of file From c42fd2580a5c0557152f53506d83dd38981c2714 Mon Sep 17 00:00:00 2001 From: Malladi Date: Mon, 28 Aug 2023 11:13:59 -0500 Subject: [PATCH 07/74] Tripal 4 tripal collections YAML file for sequence-fields: tv4g1-1509-sequence-fields --- ...l.tripalfield_collection.default_chado.yml | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml b/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml index 8459f5fb3..6f6ffb212 100644 --- a/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml +++ b/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml @@ -804,8 +804,8 @@ fields: - name: gene_sequence content_type: gene - label: Sequence - type: chado_text_type + label: Sequence Residues + type: chado_sequence_default description: One or more molecular sequences, possibly with associated annotation. cardinality: 1 required: false @@ -831,7 +831,7 @@ fields: - name: gene_length content_type: gene label: Sequence Length - type: chado_integer_type + type: chado_sequence_length_default description: The size (length) of a sequence, subsequence or region in a sequence, or range(s) of lengths. cardinality: 1 required: false @@ -854,6 +854,32 @@ fields: region: content weight: 25 + - name: gene_sequence_md5_checksum + content_type: gene + label: Sequence MD5 Checksum + type: chado_sequence_checksum_default + description: The 32-character checksum of the sequence, calculated using the MD5 algorithm. + cardinality: 1 + required: false + storage_settings: + storage_plugin_id: chado_storage + storage_plugin_settings: + base_table: feature + base_column: md5checksum + settings: + termIdSpace: data + termAccession: "2190" + display: + view: + default: + region: content + label: above + weight: 30 + form: + default: + region: content + weight: 30 + - name: gene_organism content_type: gene label: Organism From 7c432d03e8d9a9c0ea1a5a98bef18a63655957a1 Mon Sep 17 00:00:00 2001 From: Malladi Date: Mon, 28 Aug 2023 13:12:33 -0500 Subject: [PATCH 08/74] Removed ChadoLocalSourceData*.php files that were a repeat of ChadoSourceData*.php files --- .../ChadoLocalSourceDataFormatterDefault.php | 67 ----------- .../FieldType/ChadoLocalSourceDataDefault.php | 108 ------------------ .../ChadoLocalSourceDataWidgetDefault.php | 79 ------------- 3 files changed, 254 deletions(-) delete mode 100755 tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php delete mode 100755 tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php delete mode 100755 tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php diff --git a/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php b/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php deleted file mode 100755 index 9798d7dd0..000000000 --- a/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoLocalSourceDataFormatterDefault.php +++ /dev/null @@ -1,67 +0,0 @@ - $item) { - $content = "
"; -<<<<<<< HEAD -======= - $prog_vers_val = $item->get( 'programversion' )->getString() ; - if ( !empty( $prog_vers_val ) ) { - $content .= "
Software version
: " . $prog_vers_val . "
"; - } ->>>>>>> b73440286faed0b3cf68dec7fdff3e2bb4528450 - $sourcename_val = $item->get( 'sourcename' )->getString() ; - if ( !empty( $sourcename_val ) ) { - $content .= "
Source Name
: " . $sourcename_val . "
"; - } - $sourceversion_val = $item->get( 'sourceversion' )->getString() ; - if ( !empty( $sourceversion_val ) ) { - $content .= "
Source Version
: " . $sourceversion_val . "
"; - } - $sourceuri_val = $item->get( 'sourceuri' )->getString() ; - /* - if (preg_match('/^https?:/i', $sourceuri_val ) ) { - $sourceuri_val = Link::fromTextAndUrl($sourceuri_val, $sourceuri_val); - } - */ - if ( !empty( $sourceuri_val ) ) { - $content .= "
Source URI
: " . $sourceuri_val . "
"; - } - $content .= "
"; - } - $elements[$delta] = [ - '#type' => 'markup', - '#markup' => $content, - ]; - - return $elements; - } -} diff --git a/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php b/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php deleted file mode 100755 index 2ca8f71d8..000000000 --- a/tripal_chado/src/Plugin/Field/FieldType/ChadoLocalSourceDataDefault.php +++ /dev/null @@ -1,108 +0,0 @@ -getTargetEntityTypeId(); - - // Get the property terms by using the Chado table columns they map to. - $storage = \Drupal::entityTypeManager()->getStorage('chado_term_mapping'); - $mapping = $storage->load('core_mapping'); - - $record_id_term = $mapping->getColumnTermId('analysis', 'analysis_id'); - - $prog_vers_term = $mapping->getColumnTermId('analysis', 'programversion'); - $src_uri_term = $mapping->getColumnTermId('analysis', 'sourceuri'); - $src_name_term = $mapping->getColumnTermId('analysis', 'sourcename'); - $src_vers_term = $mapping->getColumnTermId('analysis', 'sourceversion'); - - // Get property terms using Chado table columns they map to. Return the properties for this field. - $properties = []; - - $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'record_id', $record_id_term, [ - 'action' => 'store_id', - 'drupal_store' => TRUE, - 'chado_table' => 'analysis', - 'chado_column' => 'analysis_id', - ]); -<<<<<<< HEAD -======= - $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'programversion', $prog_vers_term, 100, [ - 'action' => 'store', - 'chado_table' => 'analysis', - 'chado_column' => 'programversion', - ]); ->>>>>>> b73440286faed0b3cf68dec7fdff3e2bb4528450 - $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'sourceuri', $src_uri_term, 100, [ - 'action' => 'store', - 'chado_table' => 'analysis', - 'chado_column' => 'sourceuri', - ]); - $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'sourcename', $src_name_term, 200, [ - 'action' => 'store', - 'chado_table' => 'analysis', - 'chado_column' => 'sourcename', - 'delete_if_empty' => TRUE, - 'empty_value' => '', - ]); - $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'sourceversion', $src_vers_term, 100, [ - 'action' => 'store', - 'chado_table' => 'analysis', - 'chado_column' => 'sourceversion', - ]); - - return($properties); - } - -} diff --git a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php deleted file mode 100755 index 01adf86ad..000000000 --- a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoLocalSourceDataWidgetDefault.php +++ /dev/null @@ -1,79 +0,0 @@ -getValue(); - - $elements = []; - $elements['record_id'] = [ - '#type' => 'value', - '#default_value' => $item_vals['record_id'] ?? 0, - ]; -<<<<<<< HEAD -======= - - $elements['programversion'] = [ - '#title' => "Software version", - '#type' => 'textfield', - '#default_value' => $item_vals['programversion'] ?? '', - ]; ->>>>>>> b73440286faed0b3cf68dec7fdff3e2bb4528450 - $elements['sourceuri'] = [ - '#title' => "Local Source URI", - '#type' => 'textfield', - '#default_value' => $item_vals['sourceuri'] ?? '', - ]; - $elements['sourcename'] = [ - '#title' => "Local Source Name", - '#type' => 'textfield', - '#default_value' => $item_vals['sourcename'] ?? '', - ]; - $elements['sourceversion'] = [ - '#type' => 'textfield', - '#default_value' => $item_vals['sourceversion'] ?? '', - '#title' => 'Local Source Version', - ]; - - return $elements; - } - - - /** - * {@inheritDoc} - */ - public function massageFormValues(array $values, array $form, FormStateInterface $form_state) { - - // Remove any empty values that aren't mapped to a record id. - foreach ($values as $val_key => $value) { - $values[$val_key]['programversion'] = $value['programversion']; - $values[$val_key]['sourceuri'] = $value['sourceuri']; - $values[$val_key]['sourcename'] = $value['sourcename']; - $values[$val_key]['sourceversion'] = $value['sourceversion']; - } - return $values; - } - -} \ No newline at end of file From cea197f984e0e4ded110898401485e6420e47d32 Mon Sep 17 00:00:00 2001 From: Sofia Robb Date: Fri, 22 Sep 2023 21:21:33 -0700 Subject: [PATCH 09/74] This field was originally submitted by Sofia, but with changes added by Stephen --- .../ChadoSynonymFormatterDefault.php | 59 +++++ .../Field/FieldType/ChadoSynonymDefault.php | 233 ++++++++++++++++++ .../FieldWidget/ChadoSynonymWidgetDefault.php | 178 +++++++++++++ 3 files changed, 470 insertions(+) create mode 100644 tripal_chado/src/Plugin/Field/FieldFormatter/ChadoSynonymFormatterDefault.php create mode 100644 tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php create mode 100644 tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php diff --git a/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoSynonymFormatterDefault.php b/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoSynonymFormatterDefault.php new file mode 100644 index 000000000..73902391a --- /dev/null +++ b/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoSynonymFormatterDefault.php @@ -0,0 +1,59 @@ + $item) { + $value = $item->get('value')->getString(); + $list[$delta] = $value; + } + + // Also need to make sure to not return markup if the field is empty. + if (empty($list)) { + return $elements; + } + + // If more than one value has been found display all values in an unordered + // list. + if (count($list) > 1) { + $elements[0] = [ + '#theme' => 'item_list', + '#list_type' => 'ul', + '#items' => $list, + '#wrapper_attributes' => ['class' => 'container'], + ]; + return $elements; + } + + $elements[0] = [ + '#type' => 'markup', + "#markup" => $list[0] + ]; + return $elements; + } +} diff --git a/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php b/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php new file mode 100644 index 000000000..582a4479f --- /dev/null +++ b/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php @@ -0,0 +1,233 @@ +getValue('settings'); + if (!array_key_exists('storage_plugin_settings', $settings)) { + return; + } + + // Check if a corresponding synonym table exists for the + // base table. + $base_table = $form_state->getValue(['settings', 'storage_plugin_settings', 'base_table']); + $linker_table = $base_table . '_synonym'; + $chado = \Drupal::service('tripal_chado.database'); + $schema = $chado->schema(); + $linker_table_def = $schema->getTableDef($linker_table, ['format' => 'Drupal']); + if (!$linker_table_def) { + $form_state->setErrorByName('storage_plugin_settings][syn_linker_table', + 'The selected base table cannot support synonyms.'); + } + else { + $chado = \Drupal::service('tripal_chado.database'); + $schema = $chado->schema(); + $linker_table_def = $schema->getTableDef($linker_table, ['format' => 'Drupal']); + $linker_fkey_column = array_keys($linker_table_def['foreign keys'][$base_table]['columns'])[0]; + $form_state->setvalue(['settings', 'storage_plugin_settings', 'syn_linker_table'], $linker_table); + $form_state->setvalue(['settings', 'storage_plugin_settings', 'syn_linker_fkey_column'], $linker_fkey_column); + } + } + + + /** + * {@inheritdoc} + */ + public static function tripalTypes($field_definition) { + $entity_type_id = $field_definition->getTargetEntityTypeId(); + + // Get the settings for this field. + $storage_settings = $field_definition->getSetting('storage_plugin_settings'); + + $base_table = $storage_settings['base_table']; + $syn_linker_table = $storage_settings['syn_linker_table']; + $syn_linker_fkey_column = $storage_settings['syn_linker_fkey_column']; + + // If we don't have a base table then we're not ready to specify the + // properties for this field. + if (!$base_table or !$syn_linker_table) { + $record_id_term = 'SIO:000729'; + return [ + new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'record_id', $record_id_term, [ + 'action' => 'store_id', + 'drupal_store' => TRUE, + ]) + ]; + } + + // Determine the primary key of the base table. + $chado = \Drupal::service('tripal_chado.database'); + $schema = $chado->schema(); + $base_table_def = $schema->getTableDef($base_table, ['format' => 'Drupal']); + $base_pkey_col = $base_table_def['primary key']; + $synonym_table_def = $schema->getTableDef('synonym', ['format' => 'Drupal']); + $syn_linker_table_def = $schema->getTableDef($syn_linker_table, ['format' => 'Drupal']); + $syn_linker_table_pkey = $syn_linker_table_def['primary key']; + $cvterm_table_def = $schema->getTableDef('cvterm', ['format' => 'Drupal']); + + // Create variables to store the terms for the properties. We can use terms + // from Chado tables if appropriate. + $storage = \Drupal::entityTypeManager()->getStorage('chado_term_mapping'); + $mapping = $storage->load('core_mapping'); + $record_id_term = 'SIO:000729'; + + // Synonym table fields + $syn_name_term = $mapping->getColumnTermId('synonym', 'name'); + $syn_name_len = $synonym_table_def['fields']['name']['size']; + $syn_type_id_term = $mapping->getColumnTermId('synonym','type_id'); + $syn_type_name_len = $cvterm_table_def['fields']['name']['size']; + + + // Synonym linker table fields + $syn_linker_fkey_id_term = $mapping->getColumnTermId($syn_linker_table, $syn_linker_fkey_column); + $syn_linker_synonym_id_term = $mapping->getColumnTermId($syn_linker_table, 'synonym_id'); + $syn_linker_is_current_term = $mapping->getColumnTermId($syn_linker_table, 'is_current'); + $syn_linker_is_internal_term = $mapping->getColumnTermId($syn_linker_table, 'is_internal'); + $syn_linker_pub_id_term = $mapping->getColumnTermId($syn_linker_table, 'pub_id'); + + // Always store the record id of the base record that this field is + // associated with in Chado. + $properties = []; + $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'record_id', $record_id_term, [ + 'action' => 'store_id', + 'drupal_store' => TRUE, + 'chado_table' => $base_table, + 'chado_column' => $base_pkey_col + ]); + + // + // Properties corresponding to the synonym linker table. + // + $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_pkey_id', $syn_linker_synonym_id_term, [ + 'action' => 'store_pkey', + 'drupal_store' => TRUE, + 'chado_table' => $syn_linker_table, + 'chado_column' => $syn_linker_table_pkey, + ]); + $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_base_fkey_id' , $syn_linker_fkey_id_term, [ + 'action' => 'store_link', + 'drupal_store' => TRUE, + 'chado_table' => $syn_linker_table, + 'chado_column' => $syn_linker_fkey_column, + ]); + $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_synonym_fkey_id' , $syn_linker_fkey_id_term, [ + 'action' => 'store_link', + 'drupal_store' => TRUE, + 'chado_table' => $syn_linker_table, + 'chado_column' => 'synonym_id', + ]); + $properties[] = new ChadoBoolStoragePropertyType($entity_type_id, self::$id, 'is_current', $syn_linker_is_current_term, [ + 'action' => 'store', + 'chado_table' => $syn_linker_table, + 'drupal_store' => FALSE, + 'chado_column' => 'is_current', + 'empty_value' => TRUE + ]); + $properties[] = new ChadoBoolStoragePropertyType($entity_type_id, self::$id, 'is_internal', $syn_linker_is_internal_term, [ + 'action' => 'store', + 'chado_table' => $syn_linker_table, + 'drupal_store' => FALSE, + 'chado_column' => 'is_internal', + 'empty_value' => FALSE + ]); + $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_pub_id' , $syn_linker_pub_id_term, [ + 'action' => 'store', + 'drupal_store' => FALSE, + 'chado_table' => $syn_linker_table, + 'chado_column' => 'pub_id', + ]); + + // + // Properties corresponding to the synonym table. + // + $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'name', $syn_name_term, $syn_name_len, [ + 'action' => 'join', + 'path' => $syn_linker_table . '.synonym_id>synonym.synonym_id', + 'chado_column' => 'name', + 'as' => 'term_name', + 'drupal_store' => FALSE, + ]); + $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'synonym_type', $syn_type_id_term, $syn_type_name_len, [ + 'action' => 'join', + 'path' => $syn_linker_table . '.synonym_id>synonym.synonym_id;synonym.type_id>cvterm.cvterm_id', + 'chado_column' => 'name', + 'as' => 'synonym_type', + 'drupal_store' => FALSE, + ]); + + + return $properties; + } + +} \ No newline at end of file diff --git a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php new file mode 100644 index 000000000..4b5ecb5e3 --- /dev/null +++ b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php @@ -0,0 +1,178 @@ +getFieldDefinition(); + $field_settings = $field_definition->getSettings(); + $storage_settings = $field_definition->getSetting('storage_plugin_settings'); + $base_table = $storage_settings['base_table']; + $syn_linker_table = $storage_settings['syn_linker_table']; + $syn_linker_fkey_column = $storage_settings['syn_linker_fkey_column']; + + $schema = $chado->schema(); + $synonym_table_def = $schema->getTableDef('synonym', ['format' => 'Drupal']); + $syn_name_len = $synonym_table_def['fields']['name']['size']; + + // Get the default values. + $item_vals = $items[$delta]->getValue(); + $record_id = $item_vals['record_id'] ?? 0; + $linker_pkey_id = $item_vals['linker_pkey_id'] ?? 0; + $linker_base_fkey_id = $item_vals['linker_base_fkey_id'] ?? 0; + $linker_synonym_fkey_id = $item_vals['linker_synonym_fkey_id'] ?? 0; + $linker_pub_id = $item_vals['linker_pub_id'] ?? 0; + $is_current = $item_vals['is_current'] ?? TRUE; + $is_internal = $item_vals['is_internal'] ?? FALSE; + $name = $item_vals['name'] ?? ''; + $synonym_type = $item_vals['synonym_type'] ?? 'exact'; + $synonym_sgml = $item_vals['synonym_sgml'] ?? ''; + + // Get the `exact` synonym type. There are other types + // that are installed by Tripal such as BROAD, NARROW, and RELATED + // but these are meant for terms. Anyone using this field should + // simply be adding alternate names so this will always be + // an "exact" synonym. + $query = $chado->select('1:cvterm', 'cvt'); + $query->leftJoin('1:cv', 'cv', 'cv.cv_id = cvt.cv_id'); + $query->fields('cvt', ['cvterm_id', 'name', 'definition']); + $query->condition('cv.name', 'synonym_type'); + $results = $query->execute(); + $default_syn_type_id = NULL; + while ($result = $results->fetchObject()) { + if ($result->name == 'exact') { + $default_syn_type_id = $result->cvterm_id; + } + } + + // Get the default null publication for now until we have a + // decent pub lookup field. + $query = $chado->select('1:pub', 'p'); + $query->fields('p', ['pub_id']); + $query->condition('p.uniquename', 'null'); + $linker_pub_id = $query->execute()->fetchField(); + + $elements = []; + $elements['record_id'] = [ + '#type' => 'value', + '#default_value' => $record_id, + ]; + $elements['linker_pkey_id'] = [ + '#type' => 'value', + '#default_value' => $linker_pkey_id, + ]; + $elements['linker_base_fkey_id'] = [ + '#type' => 'value', + '#default_value' => $linker_base_fkey_id, + ]; + $elements['linker_synonym_fkey_id'] = [ + '#type' => 'value', + '#default_value' => $linker_synonym_fkey_id, + ]; + $elements['linker_pub_id'] = [ + '#type' => 'value', + '#default_value' => $linker_pub_id, + ]; + $elements['name'] = $element + [ + '#type' => 'textfield', + '#title' => 'Synonym', + '#default_value' => $name, + '#maxlength' => $syn_name_len, + '#description' => 'An alias or alternate name for this entity.', + '#weight' => 10, + ]; + $elements['synonym_type_id'] = [ + '#type' => 'value', + '#default_value' => $default_syn_type_id, + ]; + $elements['synonym_type'] = [ + '#type' => 'value', + '#default_value' => 'exact', + ]; + $elements['is_current'] = [ + '#type' => 'checkbox', + '#title' => t('Is this synonym current?'), + '#description' => t('If a different synonym has replaced this one, uncheck this box. '. + 'However, more than one synonym can be current.'), + '#default_value' => $is_current, + '#weight' => 12, + ]; + $elements['is_internal'] = [ + '#type' => 'checkbox', + '#title' => 'Is this synonym internal?', + '#default_value' => $is_internal, + '#description' => t('Typically a synonym exists so that somebody querying the database with an ' . + 'obsolete name can find the object they\'re looking. If the synonym has been used publicly '. + 'and deliberately (e.g. in a paper), it may also be listed in reports as a synonym. If the ' . + 'synonym was not used deliberately (e.g. there was a typo which went public), then the ' . + 'synonym is internal.'), + '#weight' => 14, + ]; + return $elements; + } + + + /** + * {@inheritDoc} + */ + public function massageFormValues(array $values, array $form, FormStateInterface $form_state) { + $chado = \Drupal::service('tripal_chado.database'); + + // Remove any empty values that don't have a name + foreach ($values as $delta => $item) { + if ($item['name'] == '') { + unset($values[$delta]); + } + } + + // Iterate through the synonyms and if a name is not + // present in the synonym table then add it. + foreach ($values as $delta => $item) { + $name = $item['name']; + $synonym_type_id = $item['synonym_type_id']; + + $query = $chado->select('1:synonym', 's'); + $query->fields('s', ['name', 'synonym_id']); + $query->condition('s.name', $item['name']); + $synonym = $query->execute()->fetchObject(); + if (!$synonym) { + $insert = $chado->insert('1:synonym'); + $insert->fields([ + 'name' => $name, + 'type_id' => $synonym_type_id, + 'synonym_sgml' => '', + ]); + $insert->execute(); + $synonym = $query->execute()->fetchObject(); + } + $values[$delta]['linker_synonym_fkey_id'] = $synonym->synonym_id; + } + return $values; + } + +} From 90948504daadb3f5e84ee04f54f69ae6e2700ffb Mon Sep 17 00:00:00 2001 From: Stephen Ficklin Date: Fri, 22 Sep 2023 23:09:16 -0700 Subject: [PATCH 10/74] slight adjustments for clarity and one bug fix --- .../FieldFormatter/ChadoSynonymFormatterDefault.php | 2 +- .../Plugin/Field/FieldType/ChadoSynonymDefault.php | 2 +- .../Field/FieldWidget/ChadoSynonymWidgetDefault.php | 11 +++++++++++ .../src/Plugin/TripalStorage/ChadoStorage.php | 8 ++++---- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoSynonymFormatterDefault.php b/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoSynonymFormatterDefault.php index 73902391a..9c415c384 100644 --- a/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoSynonymFormatterDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldFormatter/ChadoSynonymFormatterDefault.php @@ -29,7 +29,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) { $list = []; foreach($items as $delta => $item) { - $value = $item->get('value')->getString(); + $value = $item->get('name')->getString(); $list[$delta] = $value; } diff --git a/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php b/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php index 582a4479f..9f37721fc 100644 --- a/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php @@ -215,7 +215,7 @@ public static function tripalTypes($field_definition) { 'action' => 'join', 'path' => $syn_linker_table . '.synonym_id>synonym.synonym_id', 'chado_column' => 'name', - 'as' => 'term_name', + 'as' => 'synonym_name', 'drupal_store' => FALSE, ]); $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'synonym_type', $syn_type_id_term, $syn_type_name_len, [ diff --git a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php index 4b5ecb5e3..975786faa 100644 --- a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php @@ -72,6 +72,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen // Get the default null publication for now until we have a // decent pub lookup field. + // @todo: update this for a pub selector field later. $query = $chado->select('1:pub', 'p'); $query->fields('p', ['pub_id']); $query->condition('p.uniquename', 'null'); @@ -150,6 +151,16 @@ public function massageFormValues(array $values, array $form, FormStateInterface } } + // Reset the weights + $i = 0; + foreach ($values as $delta => $value) { + if ($value['value'] == '') { + continue; + } + $values[$delta]['_weight'] = $i; + $i++; + } + // Iterate through the synonyms and if a name is not // present in the synonym table then add it. foreach ($values as $delta => $item) { diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index d10a38c49..59ad0fffa 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -44,14 +44,14 @@ class ChadoStorage extends TripalStorageBase implements TripalStorageInterface { /** * The database connection for querying Chado. * - * @var Drupal\tripal_chado\Database\ChadoConnection + * @var \Drupal\tripal_chado\Database\ChadoConnection */ protected $connection; /** * A service to provide debugging for fields to developers. * - * @ var Drupal\tripal_chado\Services\ChadoFieldDebugger + * @var \Drupal\tripal_chado\Services\ChadoFieldDebugger */ protected $field_debugger; @@ -91,8 +91,8 @@ public static function create(ContainerInterface $container, array $configuratio * @param array $configuration * @param string $plugin_id * @param mixed $plugin_definition - * @param Drupal\tripal\Services\TripalLogger $logger - * @param Drupal\tripal_chado\Database\ChadoConnection $connection + * @param \Drupal\tripal\Services\TripalLogger $logger + * @param \Drupal\tripal_chado\Database\ChadoConnection $connection */ public function __construct(array $configuration, $plugin_id, $plugin_definition, TripalLogger $logger, ChadoConnection $connection, ChadoFieldDebugger $field_debugger) { parent::__construct($configuration, $plugin_id, $plugin_definition, $logger); From 1b04d597e7badfe34fa2b88e79c0146c2d063531 Mon Sep 17 00:00:00 2001 From: Stephen Ficklin Date: Fri, 22 Sep 2023 23:21:49 -0700 Subject: [PATCH 11/74] updated YML --- ...l.tripalfield_collection.default_chado.yml | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml b/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml index e471ba4b0..67f8cf3b0 100644 --- a/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml +++ b/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml @@ -987,7 +987,34 @@ fields: default: region: content weight: 90 - + + - name: gene_synonym + content_type: gene + label: Synonyms + type: chado_synonym_default + description: Alternate names, aliases or synonyms for this record. + cardinality: 0 + required: false + storage_settings: + storage_plugin_id: chado_storage + storage_plugin_settings: + base_table: feature + syn_linker_table: feature_synonym + syn_linker_fkey_column: feature_id + settings: + termIdSpace: schema + termAccession: alternateName + display: + view: + default: + region: content + label: above + weight: 10 + form: + default: + region: content + weight: 10 + - name: mrna_name content_type: mRNA label: Name From ab7b0beb0c318d2fdca6ac7267962588cb32685a Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Mon, 25 Sep 2023 13:27:21 -0600 Subject: [PATCH 12/74] Switch syn_linker* to be more generic --- ...l.tripalfield_collection.default_chado.yml | 8 +-- .../Field/FieldType/ChadoSynonymDefault.php | 64 +++++++++---------- .../FieldWidget/ChadoSynonymWidgetDefault.php | 4 +- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml b/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml index 67f8cf3b0..be4703fc2 100644 --- a/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml +++ b/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml @@ -987,7 +987,7 @@ fields: default: region: content weight: 90 - + - name: gene_synonym content_type: gene label: Synonyms @@ -999,8 +999,8 @@ fields: storage_plugin_id: chado_storage storage_plugin_settings: base_table: feature - syn_linker_table: feature_synonym - syn_linker_fkey_column: feature_id + linker_table: feature_synonym + linker_fkey_column: feature_id settings: termIdSpace: schema termAccession: alternateName @@ -1014,7 +1014,7 @@ fields: default: region: content weight: 10 - + - name: mrna_name content_type: mRNA label: Name diff --git a/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php b/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php index 9f37721fc..54e9fb389 100644 --- a/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php @@ -39,8 +39,8 @@ public static function mainPropertyName() { */ public static function defaultStorageSettings() { $settings = parent::defaultStorageSettings(); - $settings['storage_plugin_settings']['syn_linker_table'] = ''; - $settings['storage_plugin_settings']['syn_linker_fkey_column'] = ''; + $settings['storage_plugin_settings']['linker_table'] = ''; + $settings['storage_plugin_settings']['linker_fkey_column'] = ''; return $settings; } @@ -87,7 +87,7 @@ public static function storageSettingsFormValidate(array $form, FormStateInterfa $schema = $chado->schema(); $linker_table_def = $schema->getTableDef($linker_table, ['format' => 'Drupal']); if (!$linker_table_def) { - $form_state->setErrorByName('storage_plugin_settings][syn_linker_table', + $form_state->setErrorByName('storage_plugin_settings][linker_table', 'The selected base table cannot support synonyms.'); } else { @@ -95,8 +95,8 @@ public static function storageSettingsFormValidate(array $form, FormStateInterfa $schema = $chado->schema(); $linker_table_def = $schema->getTableDef($linker_table, ['format' => 'Drupal']); $linker_fkey_column = array_keys($linker_table_def['foreign keys'][$base_table]['columns'])[0]; - $form_state->setvalue(['settings', 'storage_plugin_settings', 'syn_linker_table'], $linker_table); - $form_state->setvalue(['settings', 'storage_plugin_settings', 'syn_linker_fkey_column'], $linker_fkey_column); + $form_state->setvalue(['settings', 'storage_plugin_settings', 'linker_table'], $linker_table); + $form_state->setvalue(['settings', 'storage_plugin_settings', 'linker_fkey_column'], $linker_fkey_column); } } @@ -111,12 +111,12 @@ public static function tripalTypes($field_definition) { $storage_settings = $field_definition->getSetting('storage_plugin_settings'); $base_table = $storage_settings['base_table']; - $syn_linker_table = $storage_settings['syn_linker_table']; - $syn_linker_fkey_column = $storage_settings['syn_linker_fkey_column']; + $linker_table = $storage_settings['linker_table']; + $linker_fkey_column = $storage_settings['linker_fkey_column']; // If we don't have a base table then we're not ready to specify the // properties for this field. - if (!$base_table or !$syn_linker_table) { + if (!$base_table or !$linker_table) { $record_id_term = 'SIO:000729'; return [ new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'record_id', $record_id_term, [ @@ -132,8 +132,8 @@ public static function tripalTypes($field_definition) { $base_table_def = $schema->getTableDef($base_table, ['format' => 'Drupal']); $base_pkey_col = $base_table_def['primary key']; $synonym_table_def = $schema->getTableDef('synonym', ['format' => 'Drupal']); - $syn_linker_table_def = $schema->getTableDef($syn_linker_table, ['format' => 'Drupal']); - $syn_linker_table_pkey = $syn_linker_table_def['primary key']; + $linker_table_def = $schema->getTableDef($linker_table, ['format' => 'Drupal']); + $linker_table_pkey = $linker_table_def['primary key']; $cvterm_table_def = $schema->getTableDef('cvterm', ['format' => 'Drupal']); // Create variables to store the terms for the properties. We can use terms @@ -150,11 +150,11 @@ public static function tripalTypes($field_definition) { // Synonym linker table fields - $syn_linker_fkey_id_term = $mapping->getColumnTermId($syn_linker_table, $syn_linker_fkey_column); - $syn_linker_synonym_id_term = $mapping->getColumnTermId($syn_linker_table, 'synonym_id'); - $syn_linker_is_current_term = $mapping->getColumnTermId($syn_linker_table, 'is_current'); - $syn_linker_is_internal_term = $mapping->getColumnTermId($syn_linker_table, 'is_internal'); - $syn_linker_pub_id_term = $mapping->getColumnTermId($syn_linker_table, 'pub_id'); + $linker_fkey_id_term = $mapping->getColumnTermId($linker_table, $linker_fkey_column); + $linker_synonym_id_term = $mapping->getColumnTermId($linker_table, 'synonym_id'); + $linker_is_current_term = $mapping->getColumnTermId($linker_table, 'is_current'); + $linker_is_internal_term = $mapping->getColumnTermId($linker_table, 'is_internal'); + $linker_pub_id_term = $mapping->getColumnTermId($linker_table, 'pub_id'); // Always store the record id of the base record that this field is // associated with in Chado. @@ -169,42 +169,42 @@ public static function tripalTypes($field_definition) { // // Properties corresponding to the synonym linker table. // - $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_pkey_id', $syn_linker_synonym_id_term, [ + $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_pkey_id', $linker_synonym_id_term, [ 'action' => 'store_pkey', 'drupal_store' => TRUE, - 'chado_table' => $syn_linker_table, - 'chado_column' => $syn_linker_table_pkey, + 'chado_table' => $linker_table, + 'chado_column' => $linker_table_pkey, ]); - $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_base_fkey_id' , $syn_linker_fkey_id_term, [ + $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_base_fkey_id' , $linker_fkey_id_term, [ 'action' => 'store_link', 'drupal_store' => TRUE, - 'chado_table' => $syn_linker_table, - 'chado_column' => $syn_linker_fkey_column, + 'chado_table' => $linker_table, + 'chado_column' => $linker_fkey_column, ]); - $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_synonym_fkey_id' , $syn_linker_fkey_id_term, [ + $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_synonym_fkey_id' , $linker_fkey_id_term, [ 'action' => 'store_link', 'drupal_store' => TRUE, - 'chado_table' => $syn_linker_table, + 'chado_table' => $linker_table, 'chado_column' => 'synonym_id', ]); - $properties[] = new ChadoBoolStoragePropertyType($entity_type_id, self::$id, 'is_current', $syn_linker_is_current_term, [ + $properties[] = new ChadoBoolStoragePropertyType($entity_type_id, self::$id, 'is_current', $linker_is_current_term, [ 'action' => 'store', - 'chado_table' => $syn_linker_table, + 'chado_table' => $linker_table, 'drupal_store' => FALSE, 'chado_column' => 'is_current', 'empty_value' => TRUE ]); - $properties[] = new ChadoBoolStoragePropertyType($entity_type_id, self::$id, 'is_internal', $syn_linker_is_internal_term, [ + $properties[] = new ChadoBoolStoragePropertyType($entity_type_id, self::$id, 'is_internal', $linker_is_internal_term, [ 'action' => 'store', - 'chado_table' => $syn_linker_table, + 'chado_table' => $linker_table, 'drupal_store' => FALSE, 'chado_column' => 'is_internal', 'empty_value' => FALSE ]); - $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_pub_id' , $syn_linker_pub_id_term, [ + $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_pub_id' , $linker_pub_id_term, [ 'action' => 'store', 'drupal_store' => FALSE, - 'chado_table' => $syn_linker_table, + 'chado_table' => $linker_table, 'chado_column' => 'pub_id', ]); @@ -213,14 +213,14 @@ public static function tripalTypes($field_definition) { // $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'name', $syn_name_term, $syn_name_len, [ 'action' => 'join', - 'path' => $syn_linker_table . '.synonym_id>synonym.synonym_id', + 'path' => $linker_table . '.synonym_id>synonym.synonym_id', 'chado_column' => 'name', 'as' => 'synonym_name', 'drupal_store' => FALSE, ]); $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'synonym_type', $syn_type_id_term, $syn_type_name_len, [ 'action' => 'join', - 'path' => $syn_linker_table . '.synonym_id>synonym.synonym_id;synonym.type_id>cvterm.cvterm_id', + 'path' => $linker_table . '.synonym_id>synonym.synonym_id;synonym.type_id>cvterm.cvterm_id', 'chado_column' => 'name', 'as' => 'synonym_type', 'drupal_store' => FALSE, @@ -230,4 +230,4 @@ public static function tripalTypes($field_definition) { return $properties; } -} \ No newline at end of file +} diff --git a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php index 975786faa..4f0a5bc40 100644 --- a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php @@ -33,8 +33,8 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $field_settings = $field_definition->getSettings(); $storage_settings = $field_definition->getSetting('storage_plugin_settings'); $base_table = $storage_settings['base_table']; - $syn_linker_table = $storage_settings['syn_linker_table']; - $syn_linker_fkey_column = $storage_settings['syn_linker_fkey_column']; + $linker_table = $storage_settings['linker_table']; + $linker_fkey_column = $storage_settings['linker_fkey_column']; $schema = $chado->schema(); $synonym_table_def = $schema->getTableDef('synonym', ['format' => 'Drupal']); From 7b84cdeeb0e6a41ab738b249b9d1dd229a9ccf50 Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Mon, 25 Sep 2023 13:27:48 -0600 Subject: [PATCH 13/74] Add linker_* to the yml schema for storage_plugin_settings. --- tripal_chado/tripal_chado.module | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tripal_chado/tripal_chado.module b/tripal_chado/tripal_chado.module index f78ce8cab..91871ba14 100644 --- a/tripal_chado/tripal_chado.module +++ b/tripal_chado/tripal_chado.module @@ -78,6 +78,17 @@ function tripal_chado_config_schema_info_alter(&$definitions) { 'label' => 'Table containing property columns', 'nullable' => false ]; + // Specific to linker tables. + $definitions['field.storage.tripal_entity.*']['mapping']['settings']['mapping']['storage_plugin_settings']['mapping']['linker_table'] = [ + 'type' => 'string', + 'label' => 'The linking table used by the current field.', + 'nullable' => true + ]; + $definitions['field.storage.tripal_entity.*']['mapping']['settings']['mapping']['storage_plugin_settings']['mapping']['linker_fkey_column'] = [ + 'type' => 'string', + 'label' => 'The column in the linking table which is a foreign key pointing to the base table (e.g. for feature_synonym this would be feature_id).', + 'nullable' => true + ]; // ADDITIONS TO TRIPAL FIELD COLLECTION -YML FIELD CREATION. // Adds the Base table and column information needed for all Chado fields. @@ -111,6 +122,17 @@ function tripal_chado_config_schema_info_alter(&$definitions) { 'label' => 'Table containing property columns', 'nullable' => false ]; + // Specific to linker tables. + $definitions['tripal.tripalfield_collection.*']['mapping']['fields']['sequence']['mapping']['storage_settings']['mapping']['storage_plugin_settings']['mapping']['linker_table'] = [ + 'type' => 'string', + 'label' => 'The linking table used by the current field.', + 'nullable' => true + ]; + $definitions['tripal.tripalfield_collection.*']['mapping']['fields']['sequence']['mapping']['storage_settings']['mapping']['storage_plugin_settings']['mapping']['linker_fkey_column'] = [ + 'type' => 'string', + 'label' => 'The column in the linking table which is a foreign key pointing to the base table (e.g. for feature_synonym this would be feature_id).', + 'nullable' => true + ]; } /** From e156247aba4ae372fd4c32958426b0823005a93e Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 27 Sep 2023 14:43:15 -0600 Subject: [PATCH 14/74] Sometimes value[value] not set --- .../src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php index 4f0a5bc40..b8e7be611 100644 --- a/tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldWidget/ChadoSynonymWidgetDefault.php @@ -154,7 +154,7 @@ public function massageFormValues(array $values, array $form, FormStateInterface // Reset the weights $i = 0; foreach ($values as $delta => $value) { - if ($value['value'] == '') { + if (array_key_exists('value', $value) AND $value['value'] == '') { continue; } $values[$delta]['_weight'] = $i; From 262121fbe863eec4a03fa2a94e159b298d9ea4e9 Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 27 Sep 2023 14:43:31 -0600 Subject: [PATCH 15/74] Switch to using new store_link convention. --- .../Field/FieldType/ChadoSynonymDefault.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php b/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php index 54e9fb389..316656a9b 100644 --- a/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php @@ -163,30 +163,36 @@ public static function tripalTypes($field_definition) { 'action' => 'store_id', 'drupal_store' => TRUE, 'chado_table' => $base_table, - 'chado_column' => $base_pkey_col + 'chado_column' => $base_pkey_col, ]); // // Properties corresponding to the synonym linker table. // + // E.g. feature_synonym.feature_synonym_id $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_pkey_id', $linker_synonym_id_term, [ 'action' => 'store_pkey', 'drupal_store' => TRUE, 'chado_table' => $linker_table, 'chado_column' => $linker_table_pkey, ]); + // E.g. feature.feature_id => feature_synonym.feature_id $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_base_fkey_id' , $linker_fkey_id_term, [ 'action' => 'store_link', 'drupal_store' => TRUE, - 'chado_table' => $linker_table, - 'chado_column' => $linker_fkey_column, + 'left_table' => $base_table, + 'left_table_id' => $base_pkey_col, + 'right_table' => $linker_table, + 'right_table_id' => $linker_fkey_column, ]); + // E.g. feature_synonym.synonym_id $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_synonym_fkey_id' , $linker_fkey_id_term, [ - 'action' => 'store_link', + 'action' => 'store', 'drupal_store' => TRUE, 'chado_table' => $linker_table, 'chado_column' => 'synonym_id', ]); + // E.g. feature_synonym.is_current $properties[] = new ChadoBoolStoragePropertyType($entity_type_id, self::$id, 'is_current', $linker_is_current_term, [ 'action' => 'store', 'chado_table' => $linker_table, @@ -194,6 +200,7 @@ public static function tripalTypes($field_definition) { 'chado_column' => 'is_current', 'empty_value' => TRUE ]); + // E.g. feature_synonym.is_internal $properties[] = new ChadoBoolStoragePropertyType($entity_type_id, self::$id, 'is_internal', $linker_is_internal_term, [ 'action' => 'store', 'chado_table' => $linker_table, @@ -201,6 +208,7 @@ public static function tripalTypes($field_definition) { 'chado_column' => 'is_internal', 'empty_value' => FALSE ]); + // E.g. feature_synonym.pub_id $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_pub_id' , $linker_pub_id_term, [ 'action' => 'store', 'drupal_store' => FALSE, @@ -211,6 +219,7 @@ public static function tripalTypes($field_definition) { // // Properties corresponding to the synonym table. // + // E.g. feature_synonym.synonym_id>synonym.synonym_id : synonym.name as synonym_name $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'name', $syn_name_term, $syn_name_len, [ 'action' => 'join', 'path' => $linker_table . '.synonym_id>synonym.synonym_id', @@ -218,6 +227,7 @@ public static function tripalTypes($field_definition) { 'as' => 'synonym_name', 'drupal_store' => FALSE, ]); + // E.g. feature_synonym.synonym_id>synonym.synonym_id;synonym.type_id>cvterm.cvterm_id : cvterm.name as synonym_type $properties[] = new ChadoVarCharStoragePropertyType($entity_type_id, self::$id, 'synonym_type', $syn_type_id_term, $syn_type_name_len, [ 'action' => 'join', 'path' => $linker_table . '.synonym_id>synonym.synonym_id;synonym.type_id>cvterm.cvterm_id', From 31c686b8a88275779bcbc7fa25a9cb147f63042f Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 27 Sep 2023 15:45:12 -0600 Subject: [PATCH 16/74] Fix ID. --- tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php b/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php index 316656a9b..e8161dc08 100644 --- a/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldType/ChadoSynonymDefault.php @@ -16,7 +16,7 @@ * Plugin implementation of Tripal string field type. * * @FieldType( - * id = "chado_feature_synonym_default", + * id = "chado_synonym_default", * label = @Translation("Chado Synonym"), * description = @Translation("A chado syonym"), * default_widget = "chado_synonym_widget_default", From fd99c94c457916f4c51552cdac41f2411f506bdb Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 27 Sep 2023 15:45:28 -0600 Subject: [PATCH 17/74] Ensure field is added to all content types it applies to. --- ...l.tripalfield_collection.default_chado.yml | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml b/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml index be4703fc2..82f293f35 100644 --- a/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml +++ b/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml @@ -1228,6 +1228,33 @@ fields: region: content weight: 90 + - name: mrna_synonym + content_type: mRNA + label: Synonyms + type: chado_synonym_default + description: Alternate names, aliases or synonyms for this record. + cardinality: 0 + required: false + storage_settings: + storage_plugin_id: chado_storage + storage_plugin_settings: + base_table: feature + linker_table: feature_synonym + linker_fkey_column: feature_id + settings: + termIdSpace: schema + termAccession: alternateName + display: + view: + default: + region: content + label: above + weight: 10 + form: + default: + region: content + weight: 10 + - name: phylotree_name content_type: phylotree label: Name @@ -1548,6 +1575,33 @@ fields: region: content weight: 20 + - name: dna_library_synonym + content_type: dna_library + label: Synonyms + type: chado_synonym_default + description: Alternate names, aliases or synonyms for this record. + cardinality: 0 + required: false + storage_settings: + storage_plugin_id: chado_storage + storage_plugin_settings: + base_table: library + linker_table: library_synonym + linker_fkey_column: library_id + settings: + termIdSpace: schema + termAccession: alternateName + display: + view: + default: + region: content + label: above + weight: 10 + form: + default: + region: content + weight: 10 + - name: genome_assembly_name content_type: genome_assembly label: Name @@ -2353,6 +2407,33 @@ fields: region: content weight: 90 + - name: qtl_synonym + content_type: QTL + label: Synonyms + type: chado_synonym_default + description: Alternate names, aliases or synonyms for this record. + cardinality: 0 + required: false + storage_settings: + storage_plugin_id: chado_storage + storage_plugin_settings: + base_table: feature + linker_table: feature_synonym + linker_fkey_column: feature_id + settings: + termIdSpace: schema + termAccession: alternateName + display: + view: + default: + region: content + label: above + weight: 10 + form: + default: + region: content + weight: 10 + - name: sequence_variant_name content_type: sequence_variant label: Name @@ -2566,6 +2647,33 @@ fields: region: content weight: 90 + - name: sequence_variant_synonym + content_type: sequence_variant + label: Synonyms + type: chado_synonym_default + description: Alternate names, aliases or synonyms for this record. + cardinality: 0 + required: false + storage_settings: + storage_plugin_id: chado_storage + storage_plugin_settings: + base_table: feature + linker_table: feature_synonym + linker_fkey_column: feature_id + settings: + termIdSpace: schema + termAccession: alternateName + display: + view: + default: + region: content + label: above + weight: 10 + form: + default: + region: content + weight: 10 + - name: genetic_marker_name content_type: genetic_marker label: Name @@ -2779,6 +2887,33 @@ fields: region: content weight: 90 + - name: genetic_marker_synonym + content_type: genetic_marker + label: Synonyms + type: chado_synonym_default + description: Alternate names, aliases or synonyms for this record. + cardinality: 0 + required: false + storage_settings: + storage_plugin_id: chado_storage + storage_plugin_settings: + base_table: feature + linker_table: feature_synonym + linker_fkey_column: feature_id + settings: + termIdSpace: schema + termAccession: alternateName + display: + view: + default: + region: content + label: above + weight: 10 + form: + default: + region: content + weight: 10 + - name: phenotypic_marker_name content_type: phenotypic_marker label: Name @@ -2992,6 +3127,33 @@ fields: region: content weight: 90 + - name: phenotypic_marker_synonym + content_type: phenotypic_marker + label: Synonyms + type: chado_synonym_default + description: Alternate names, aliases or synonyms for this record. + cardinality: 0 + required: false + storage_settings: + storage_plugin_id: chado_storage + storage_plugin_settings: + base_table: feature + linker_table: feature_synonym + linker_fkey_column: feature_id + settings: + termIdSpace: schema + termAccession: alternateName + display: + view: + default: + region: content + label: above + weight: 10 + form: + default: + region: content + weight: 10 + - name: germplasm_name content_type: germplasm label: Name From 42cb9193cc42fc8765ac14084dc01e0084e57c6f Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Thu, 28 Sep 2023 16:15:59 -0600 Subject: [PATCH 18/74] Use -1 for unlimited. --- ...tripal.tripalfield_collection.default_chado.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml b/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml index 82f293f35..8e3a7f002 100644 --- a/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml +++ b/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml @@ -993,7 +993,7 @@ fields: label: Synonyms type: chado_synonym_default description: Alternate names, aliases or synonyms for this record. - cardinality: 0 + cardinality: -1 required: false storage_settings: storage_plugin_id: chado_storage @@ -1233,7 +1233,7 @@ fields: label: Synonyms type: chado_synonym_default description: Alternate names, aliases or synonyms for this record. - cardinality: 0 + cardinality: -1 required: false storage_settings: storage_plugin_id: chado_storage @@ -1580,7 +1580,7 @@ fields: label: Synonyms type: chado_synonym_default description: Alternate names, aliases or synonyms for this record. - cardinality: 0 + cardinality: -1 required: false storage_settings: storage_plugin_id: chado_storage @@ -2412,7 +2412,7 @@ fields: label: Synonyms type: chado_synonym_default description: Alternate names, aliases or synonyms for this record. - cardinality: 0 + cardinality: -1 required: false storage_settings: storage_plugin_id: chado_storage @@ -2652,7 +2652,7 @@ fields: label: Synonyms type: chado_synonym_default description: Alternate names, aliases or synonyms for this record. - cardinality: 0 + cardinality: -1 required: false storage_settings: storage_plugin_id: chado_storage @@ -2892,7 +2892,7 @@ fields: label: Synonyms type: chado_synonym_default description: Alternate names, aliases or synonyms for this record. - cardinality: 0 + cardinality: -1 required: false storage_settings: storage_plugin_id: chado_storage @@ -3132,7 +3132,7 @@ fields: label: Synonyms type: chado_synonym_default description: Alternate names, aliases or synonyms for this record. - cardinality: 0 + cardinality: -1 required: false storage_settings: storage_plugin_id: chado_storage From baaa1ea3c4354d805ec674ad9192997200df8827 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Mon, 16 Oct 2023 11:23:50 -0600 Subject: [PATCH 19/74] Add method for store_id -untested right now. --- .../src/Plugin/TripalStorage/ChadoStorage.php | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index 14326ddbe..24932740c 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -1091,6 +1091,77 @@ protected function buildChadoRecords($values, bool $is_store) { ]; } + /** + * Add chado record information for a specific ChadoStorageProperty + * where the action is store_id. + * + * STORE ID: stores the primary key value for a core table in chado. + * + * Note: There may be more core tables in properties for this field + * then just the base table. For example, a field involving a two-join + * linker table will include two core tables. + * + * @param array $records + * The current set of chado records. This method will update this array. + * @param array $storage_settings + * The storage settings for the current property. This is all the information + * from the property type. + * @param array $context + * A set of values to provide context. These a pre-computed in the parent method + * to reduce code duplication when a task is done for all/many storage properties + * regardless of their action. + * @param StoragePropertyValue $prop_value + * The value object for the property we are adding records for. + * Note: We will always have a StoragePropertyValue for a property even if + * the value is not set. This method is expected to check if the value is empty or not. + */ + protected function buildChadoRecords_store_id(array &$records, array $storage_settings, array &$context, StoragePropertyValue $prop_value) { + + // Get the Chado table this specific property works with. + // Use the base table as a default for properties which do not specify + // the chado table (e.g. single value fields). + $chado_table = $context['base_table']; + if (array_key_exists('chado_table', $prop_storage_settings)) { + $chado_table = $prop_storage_settings['chado_table']; + } + // Now determine the primary key for the chado table. + $schema = $this->connection->schema(); + $chado_table_def = $schema->getTableDef($chado_table, ['format' => 'drupal']); + $chado_table_pkey = $chado_table_def['primary key']; + + // Get the value if it is set. + $record_id = $prop_value->getValue(); + + // If the record_id is zero then this is a brand-new value for + // this property. Let's set it to be replaced in the hopes that + // some other property has already been inserted and has the ID. + if ($record_id == 0) { + $records[$chado_table][0]['conditions'][$chado_table_pkey] = [ + 'value' => [ + 'REPLACE_BASE_RECORD_ID', + $context['base_table'] + ], + 'operation' => $operation + ]; + // Now we add the chado table to our array of core tables + // so that we can replace it with the value for the record later. + if (!array_key_exists($chado_table, $context['base_record_ids'])) { + $context['base_record_ids'][$chado_table] = $record_id; + } + } + // However, if the record_id was set when the values were passed in, + // then we want to set it here and add it to the array of core ids + // for use later when replacing base record ids. + else { + $records[$chado_table][0]['conditions'][$chado_table_pkey] = [ + 'value' => $record_id, + 'operation' => $operation + ]; + + $context['base_record_ids'][$chado_table] = $record_id; + } + } + /** * * @param array $records From b0440f12402c4acb7bd4a5dce289f6218f97f6e8 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Mon, 16 Oct 2023 11:42:58 -0600 Subject: [PATCH 20/74] Start moving shared info to a context array. --- .../src/Plugin/TripalStorage/ChadoStorage.php | 61 +++++++++---------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index 24932740c..1220d6576 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -793,10 +793,15 @@ protected function buildChadoRecords($values, bool $is_store) { $schema = $this->connection->schema(); $records = []; - $base_record_ids = []; $this->field_debugger->reportValues($values, 'The values submitted to ChadoStorage'); + // Define an array containing context information that will be used + // for all the actions. + $context = [ + 'base_record_ids' => [], + ]; + // Iterate through the value objects. foreach ($values as $field_name => $deltas) { @@ -849,28 +854,13 @@ protected function buildChadoRecords($values, bool $is_store) { // Get the base table definitions for the field. $base_table = $storage_plugin_settings['base_table']; - $base_table_def = $schema->getTableDef($base_table, ['format' => 'drupal']); - $base_table_pkey = $base_table_def['primary key']; // Get the Chado table this specific property works with. // Use the base table as a default for properties which do not specify // the chado table (e.g. single value fields). $chado_table = $base_table; - $chado_table_def = $base_table_def; - $chado_table_pkey = $base_table_pkey; if (array_key_exists('chado_table', $prop_storage_settings)) { $chado_table = $prop_storage_settings['chado_table']; - $chado_table_def = $schema->getTableDef($chado_table, ['format' => 'drupal']); - $chado_table_pkey = $chado_table_def['primary key']; - } - // Properties with a store_link action use left/right table notation. - // The left table.left_table_id include the information for the value - // to be set in this property so use them as equalivalent to the - // chado table used in other actions. This also allows us to use - // the base table of the field as a default for this. - if (array_key_exists('left_table', $prop_storage_settings)) { - $chado_table = $prop_storage_settings['left_table']; - $chado_table_pkey = $prop_storage_settings['left_table_id']; } // Now for each action type, set the conditions and fields for @@ -882,6 +872,10 @@ protected function buildChadoRecords($values, bool $is_store) { // linker table will include two core tables. // ................................................................ if ($action == 'store_id') { + + $chado_table_def = $this->connection->schema()->getTableDef($chado_table, ['format' => 'drupal']); + $chado_table_pkey = $chado_table_def['primary key']; + $record_id = $prop_value->getValue(); // If the record_id is zero then this is a brand-new value for // this property. Let's set it to be replaced in the hopes that @@ -890,8 +884,8 @@ protected function buildChadoRecords($values, bool $is_store) { $records[$chado_table][0]['conditions'][$chado_table_pkey] = ['value' => ['REPLACE_BASE_RECORD_ID', $base_table], 'operation' => $operation]; // Now we add the chado table to our array of core tables // so that we can replace it with the value for the record later. - if (!array_key_exists($chado_table, $base_record_ids)) { - $base_record_ids[$chado_table] = $record_id; + if (!array_key_exists($chado_table, $context['base_record_ids'])) { + $context['base_record_ids'][$chado_table] = $record_id; } } // However, if the record_id was set when the values were passed in, @@ -899,7 +893,7 @@ protected function buildChadoRecords($values, bool $is_store) { // for use later when replacing base record ids. else { $records[$chado_table][0]['conditions'][$chado_table_pkey] = ['value' => $record_id, 'operation' => $operation]; - $base_record_ids[$chado_table] = $record_id; + $context['base_record_ids'][$chado_table] = $record_id; } } // STORE PKEY: stores the primary key value of a linking table. @@ -908,6 +902,10 @@ protected function buildChadoRecords($values, bool $is_store) { // linking tables are handled after. // ................................................................ if ($action == 'store_pkey') { + + $chado_table_def = $this->connection->schema()->getTableDef($chado_table, ['format' => 'drupal']); + $chado_table_pkey = $chado_table_def['primary key']; + $link_record_id = $prop_value->getValue(); $records[$chado_table][$delta]['conditions'][$chado_table_pkey] = ['value' => $link_record_id, 'operation' => $operation]; } @@ -932,7 +930,7 @@ protected function buildChadoRecords($values, bool $is_store) { $linker_id = $prop_storage_settings['right_table_id']; // Then check if the right table has a store_id and if so, use it instead. // (e.g. analysisfeature.analysis_id = analysis.analysis_id) - if (array_key_exists($prop_storage_settings['right_table'], $base_record_ids)) { + if (array_key_exists($prop_storage_settings['right_table'], $context['base_record_ids'])) { $link_base = $prop_storage_settings['right_table']; $link_base_id = $prop_storage_settings['right_table_id']; $linker = $chado_table; @@ -1049,14 +1047,14 @@ protected function buildChadoRecords($values, bool $is_store) { // If the core table is set in the base record ids array and the // value is not 0 then we can set this chado field now! - if (array_key_exists($core_table, $base_record_ids) and $base_record_ids[$core_table] != 0) { - $records[$table_name][$delta]['fields'][$chado_column] = $base_record_ids[$core_table]; + if (array_key_exists($core_table, $context['base_record_ids']) and $context['base_record_ids'][$core_table] != 0) { + $records[$table_name][$delta]['fields'][$chado_column] = $context['base_record_ids'][$core_table]; } // If the base record ID is 0 then this is an insert and we // don't yet have the base record ID. So, leave in the message // to replace the ID so we can do so later. - if (array_key_exists($base_table, $base_record_ids) and $base_record_ids[$base_table] != 0) { - $records[$table_name][$delta]['fields'][$chado_column] = $base_record_ids[$base_table]; + if (array_key_exists($base_table, $context['base_record_ids']) and $context['base_record_ids'][$base_table] != 0) { + $records[$table_name][$delta]['fields'][$chado_column] = $context['base_record_ids'][$base_table]; } } @@ -1068,14 +1066,14 @@ protected function buildChadoRecords($values, bool $is_store) { // If the core table is set in the base record ids array and the // value is not 0 then we can set this condition now! - if (array_key_exists($core_table, $base_record_ids) and $base_record_ids[$core_table] != 0) { - $records[$table_name][$delta]['conditions'][$chado_column] = $base_record_ids[$core_table]; + if (array_key_exists($core_table, $context['base_record_ids']) and $context['base_record_ids'][$core_table] != 0) { + $records[$table_name][$delta]['conditions'][$chado_column] = $context['base_record_ids'][$core_table]; } // If the base record ID is 0 then this is an insert and we // don't yet have the base record ID. So, leave in the message // to replace the ID so we can do so later. - if (array_key_exists($base_table, $base_record_ids) and $base_record_ids[$base_table] != 0) { - $records[$table_name][$delta]['conditions'][$chado_column]['value'] = $base_record_ids[$base_table]; + if (array_key_exists($base_table, $context['base_record_ids']) and $context['base_record_ids'][$base_table] != 0) { + $records[$table_name][$delta]['conditions'][$chado_column]['value'] = $context['base_record_ids'][$base_table]; } } @@ -1083,10 +1081,10 @@ protected function buildChadoRecords($values, bool $is_store) { } } - $this->field_debugger->summarizeBuiltRecords($base_record_ids, $records); + $this->field_debugger->summarizeBuiltRecords($context['base_record_ids'], $records); return [ - 'base_tables' => $base_record_ids, + 'base_tables' => $context['base_record_ids'], 'records' => $records ]; } @@ -1125,8 +1123,7 @@ protected function buildChadoRecords_store_id(array &$records, array $storage_se $chado_table = $prop_storage_settings['chado_table']; } // Now determine the primary key for the chado table. - $schema = $this->connection->schema(); - $chado_table_def = $schema->getTableDef($chado_table, ['format' => 'drupal']); + $chado_table_def = $this->connection->schema()->getTableDef($chado_table, ['format' => 'drupal']); $chado_table_pkey = $chado_table_def['primary key']; // Get the value if it is set. From 6ee2241e0c7796a0974b3d9b46abef0d63ba4e9e Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Mon, 16 Oct 2023 12:03:55 -0600 Subject: [PATCH 21/74] Move more information into the context. --- .../src/Plugin/TripalStorage/ChadoStorage.php | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index 1220d6576..606d1f678 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -790,8 +790,6 @@ protected function setPropValues(&$values, $records) { * An associative array. */ protected function buildChadoRecords($values, bool $is_store) { - - $schema = $this->connection->schema(); $records = []; $this->field_debugger->reportValues($values, 'The values submitted to ChadoStorage'); @@ -812,6 +810,7 @@ protected function buildChadoRecords($values, bool $is_store) { ['@field' => $field_name])); continue; } + $storage_plugin_settings = $definition->getSettings()['storage_plugin_settings']; foreach ($deltas as $delta => $keys) { foreach ($keys as $key => $info) { @@ -822,25 +821,16 @@ protected function buildChadoRecords($values, bool $is_store) { ['@field' => $field_name])); continue; } - $prop_value = $info['value']; - // Retrieve the property type for this value. + $prop_value = $info['value']; $prop_type = $this->getPropertyType($field_name, $key); - - // Retrieve the operation to be used for searching and if not set, use equals as the default. - $operation = array_key_exists('operation', $info) ? $info['operation'] : '='; - - // Retrieve important field settings. - $field_label = $definition->getLabel(); - $field_settings = $definition->getSettings(); - $storage_plugin_settings = $field_settings['storage_plugin_settings']; $prop_storage_settings = $prop_type->getStorageSettings(); // Make sure we have an action for this property. if (!array_key_exists('action', $prop_storage_settings)) { $this->logger->error($this->t('Cannot store the property, @field.@prop ("@label"), in Chado. The property is missing an action in the property settings: @settings', ['@field' => $field_name, '@prop' => $key, - '@label' => $field_label, '@settings' => print_r($prop_storage_settings, TRUE)])); + '@label' => $definition->getLabel(), '@settings' => print_r($prop_storage_settings, TRUE)])); continue; } $action = $prop_storage_settings['action']; @@ -851,18 +841,19 @@ protected function buildChadoRecords($values, bool $is_store) { ['@field' => $field_name, '@prop' => $key])); continue; } - - // Get the base table definitions for the field. - $base_table = $storage_plugin_settings['base_table']; + $context['base_table'] = $storage_plugin_settings['base_table']; // Get the Chado table this specific property works with. // Use the base table as a default for properties which do not specify // the chado table (e.g. single value fields). - $chado_table = $base_table; + $chado_table = $context['base_table']; if (array_key_exists('chado_table', $prop_storage_settings)) { $chado_table = $prop_storage_settings['chado_table']; } + // Retrieve the operation to be used for searching and if not set, use equals as the default. + $context['operation'] = array_key_exists('operation', $info) ? $info['operation'] : '='; + // Now for each action type, set the conditions and fields for // selecting chado records based on the other properties supplied. // ---------------------------------------------------------------- @@ -881,7 +872,7 @@ protected function buildChadoRecords($values, bool $is_store) { // this property. Let's set it to be replaced in the hopes that // some other property has already been inserted and has the ID. if ($record_id == 0) { - $records[$chado_table][0]['conditions'][$chado_table_pkey] = ['value' => ['REPLACE_BASE_RECORD_ID', $base_table], 'operation' => $operation]; + $records[$chado_table][0]['conditions'][$chado_table_pkey] = ['value' => ['REPLACE_BASE_RECORD_ID', $chado_table], 'operation' => $context['operation']]; // Now we add the chado table to our array of core tables // so that we can replace it with the value for the record later. if (!array_key_exists($chado_table, $context['base_record_ids'])) { @@ -892,7 +883,7 @@ protected function buildChadoRecords($values, bool $is_store) { // then we want to set it here and add it to the array of core ids // for use later when replacing base record ids. else { - $records[$chado_table][0]['conditions'][$chado_table_pkey] = ['value' => $record_id, 'operation' => $operation]; + $records[$chado_table][0]['conditions'][$chado_table_pkey] = ['value' => $record_id, 'operation' => $context['operation']]; $context['base_record_ids'][$chado_table] = $record_id; } } @@ -907,7 +898,7 @@ protected function buildChadoRecords($values, bool $is_store) { $chado_table_pkey = $chado_table_def['primary key']; $link_record_id = $prop_value->getValue(); - $records[$chado_table][$delta]['conditions'][$chado_table_pkey] = ['value' => $link_record_id, 'operation' => $operation]; + $records[$chado_table][$delta]['conditions'][$chado_table_pkey] = ['value' => $link_record_id, 'operation' => $context['operation']]; } // STORE LINK: performs a join between two tables, one of which is a // core table and one of which is a linking table. The value which is saved @@ -956,7 +947,7 @@ protected function buildChadoRecords($values, bool $is_store) { // but will cause problems with double-hops and all token replacement. $bc_chado_table = $prop_storage_settings['chado_table']; $bc_chado_column = $prop_storage_settings['chado_column']; - $records[$bc_chado_table][$delta]['fields'][$bc_chado_column] = ['REPLACE_BASE_RECORD_ID', $base_table]; + $records[$bc_chado_table][$delta]['fields'][$bc_chado_column] = ['REPLACE_BASE_RECORD_ID', $context['base_table']]; $this->logger->warning( 'We had to use backwards compatible mode for :name.:key property type with an action of store_link.' .' Please update the code for this field to use left/right table notation for the store_link property.' @@ -1038,6 +1029,7 @@ protected function buildChadoRecords($values, bool $is_store) { // before chado storage was called. // Note: We have not yet done any querying ;-p // ----------------------------------------------------------------------- + $base_table = $context['base_table']; foreach ($records as $table_name => $deltas) { foreach ($deltas as $delta => $record) { // First for all the fields... @@ -1138,7 +1130,7 @@ protected function buildChadoRecords_store_id(array &$records, array $storage_se 'REPLACE_BASE_RECORD_ID', $context['base_table'] ], - 'operation' => $operation + 'operation' => $context['operation'] ]; // Now we add the chado table to our array of core tables // so that we can replace it with the value for the record later. @@ -1152,7 +1144,7 @@ protected function buildChadoRecords_store_id(array &$records, array $storage_se else { $records[$chado_table][0]['conditions'][$chado_table_pkey] = [ 'value' => $record_id, - 'operation' => $operation + 'operation' => $context['operation'] ]; $context['base_record_ids'][$chado_table] = $record_id; From 677772538db0c24f9fbd0df724b7ee2bf026484b Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Mon, 16 Oct 2023 13:21:23 -0600 Subject: [PATCH 22/74] Move store_id bit to it's own method. --- .../src/Plugin/TripalStorage/ChadoStorage.php | 31 ++++--------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index 606d1f678..652fe03c1 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -11,6 +11,8 @@ use Drupal\tripal_chado\Database\ChadoConnection; use Drupal\tripal_chado\Services\ChadoFieldDebugger; +use Drupal\tripal\TripalStorage\StoragePropertyValue; + /** * Chado implementation of the TripalStorageInterface. * @@ -846,6 +848,7 @@ protected function buildChadoRecords($values, bool $is_store) { // Get the Chado table this specific property works with. // Use the base table as a default for properties which do not specify // the chado table (e.g. single value fields). + /* TO BE REMOVED LATER */ $chado_table = $context['base_table']; if (array_key_exists('chado_table', $prop_storage_settings)) { $chado_table = $prop_storage_settings['chado_table']; @@ -863,29 +866,7 @@ protected function buildChadoRecords($values, bool $is_store) { // linker table will include two core tables. // ................................................................ if ($action == 'store_id') { - - $chado_table_def = $this->connection->schema()->getTableDef($chado_table, ['format' => 'drupal']); - $chado_table_pkey = $chado_table_def['primary key']; - - $record_id = $prop_value->getValue(); - // If the record_id is zero then this is a brand-new value for - // this property. Let's set it to be replaced in the hopes that - // some other property has already been inserted and has the ID. - if ($record_id == 0) { - $records[$chado_table][0]['conditions'][$chado_table_pkey] = ['value' => ['REPLACE_BASE_RECORD_ID', $chado_table], 'operation' => $context['operation']]; - // Now we add the chado table to our array of core tables - // so that we can replace it with the value for the record later. - if (!array_key_exists($chado_table, $context['base_record_ids'])) { - $context['base_record_ids'][$chado_table] = $record_id; - } - } - // However, if the record_id was set when the values were passed in, - // then we want to set it here and add it to the array of core ids - // for use later when replacing base record ids. - else { - $records[$chado_table][0]['conditions'][$chado_table_pkey] = ['value' => $record_id, 'operation' => $context['operation']]; - $context['base_record_ids'][$chado_table] = $record_id; - } + $this->buildChadoRecords_store_id($records, $prop_storage_settings, $context, $prop_value); } // STORE PKEY: stores the primary key value of a linking table. // NOTE: A linking table is not a core table. This is important because @@ -1111,8 +1092,8 @@ protected function buildChadoRecords_store_id(array &$records, array $storage_se // Use the base table as a default for properties which do not specify // the chado table (e.g. single value fields). $chado_table = $context['base_table']; - if (array_key_exists('chado_table', $prop_storage_settings)) { - $chado_table = $prop_storage_settings['chado_table']; + if (array_key_exists('chado_table', $storage_settings)) { + $chado_table = $storage_settings['chado_table']; } // Now determine the primary key for the chado table. $chado_table_def = $this->connection->schema()->getTableDef($chado_table, ['format' => 'drupal']); From f56a5a681f70000374bf42529c3ecacf772faa7a Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Mon, 16 Oct 2023 13:41:56 -0600 Subject: [PATCH 23/74] Move store_pkey into it's own method. --- .../src/Plugin/TripalStorage/ChadoStorage.php | 71 +++++++++++++++---- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index 652fe03c1..80ac7cf6f 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -866,7 +866,7 @@ protected function buildChadoRecords($values, bool $is_store) { // linker table will include two core tables. // ................................................................ if ($action == 'store_id') { - $this->buildChadoRecords_store_id($records, $prop_storage_settings, $context, $prop_value); + $this->buildChadoRecords_store_id($records, $delta, $prop_storage_settings, $context, $prop_value); } // STORE PKEY: stores the primary key value of a linking table. // NOTE: A linking table is not a core table. This is important because @@ -874,12 +874,7 @@ protected function buildChadoRecords($values, bool $is_store) { // linking tables are handled after. // ................................................................ if ($action == 'store_pkey') { - - $chado_table_def = $this->connection->schema()->getTableDef($chado_table, ['format' => 'drupal']); - $chado_table_pkey = $chado_table_def['primary key']; - - $link_record_id = $prop_value->getValue(); - $records[$chado_table][$delta]['conditions'][$chado_table_pkey] = ['value' => $link_record_id, 'operation' => $context['operation']]; + $this->buildChadoRecords_store_pkey($records, $delta, $prop_storage_settings, $context, $prop_value); } // STORE LINK: performs a join between two tables, one of which is a // core table and one of which is a linking table. The value which is saved @@ -896,8 +891,8 @@ protected function buildChadoRecords($values, bool $is_store) { // fields below to ensure the ID is replaced. // Start by assuming the left table is the base/core table // (e.g. feature.feature_id = featureprop.feature_id). - $link_base = $chado_table; - $link_base_id = $chado_table_pkey; + $link_base = $prop_storage_settings['left_table']; + $link_base_id = $prop_storage_settings['left_table_id']; $linker = $prop_storage_settings['right_table']; $linker_id = $prop_storage_settings['right_table_id']; // Then check if the right table has a store_id and if so, use it instead. @@ -905,8 +900,8 @@ protected function buildChadoRecords($values, bool $is_store) { if (array_key_exists($prop_storage_settings['right_table'], $context['base_record_ids'])) { $link_base = $prop_storage_settings['right_table']; $link_base_id = $prop_storage_settings['right_table_id']; - $linker = $chado_table; - $linker_id = $chado_table_pkey; + $linker = $prop_storage_settings['left_table']; + $linker_id = $prop_storage_settings['left_table_id']; } // @debug print "We decided it should be BASE $link_base.$link_base_id => LINKER $linker.$linker_id.\n"; // We want to ensure that the linker table has a field added with @@ -1074,6 +1069,9 @@ protected function buildChadoRecords($values, bool $is_store) { * * @param array $records * The current set of chado records. This method will update this array. + * @param int $delta + * The position in the values array the current property type stands + * and thus the position in the records array it should be. * @param array $storage_settings * The storage settings for the current property. This is all the information * from the property type. @@ -1086,7 +1084,7 @@ protected function buildChadoRecords($values, bool $is_store) { * Note: We will always have a StoragePropertyValue for a property even if * the value is not set. This method is expected to check if the value is empty or not. */ - protected function buildChadoRecords_store_id(array &$records, array $storage_settings, array &$context, StoragePropertyValue $prop_value) { + protected function buildChadoRecords_store_id(array &$records, int $delta, array $storage_settings, array &$context, StoragePropertyValue $prop_value) { // Get the Chado table this specific property works with. // Use the base table as a default for properties which do not specify @@ -1132,6 +1130,55 @@ protected function buildChadoRecords_store_id(array &$records, array $storage_se } } + /** + * Add chado record information for a specific ChadoStorageProperty + * where the action is store_pkey. + * + * STORE PKEY: stores the primary key value of a linking table. + * + * NOTE: A linking table is not a core table. This is important because + * during insert and update, the core tables are handled first and then + * linking tables are handled after. + * + * @param array $records + * The current set of chado records. This method will update this array. + * @param int $delta + * The position in the values array the current property type stands + * and thus the position in the records array it should be. + * @param array $storage_settings + * The storage settings for the current property. This is all the information + * from the property type. + * @param array $context + * A set of values to provide context. These a pre-computed in the parent method + * to reduce code duplication when a task is done for all/many storage properties + * regardless of their action. + * @param StoragePropertyValue $prop_value + * The value object for the property we are adding records for. + * Note: We will always have a StoragePropertyValue for a property even if + * the value is not set. This method is expected to check if the value is empty or not. + */ + protected function buildChadoRecords_store_pkey(array &$records, int $delta, array $storage_settings, array &$context, StoragePropertyValue $prop_value) { + + // Get the Chado table this specific property works with. + // Use the base table as a default for properties which do not specify + // the chado table (e.g. single value fields). + $chado_table = $context['base_table']; + if (array_key_exists('chado_table', $storage_settings)) { + $chado_table = $storage_settings['chado_table']; + } + // Now determine the primary key for the chado table. + $chado_table_def = $this->connection->schema()->getTableDef($chado_table, ['format' => 'drupal']); + $chado_table_pkey = $chado_table_def['primary key']; + + $link_record_id = $prop_value->getValue(); + + $records[$chado_table][$delta]['conditions'][$chado_table_pkey] = [ + 'value' => $link_record_id, + 'operation' => $context['operation'] + ]; + + } + /** * * @param array $records From 325a0c1cd6e08d1da11d30b79fd284dac1a1fe0a Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Mon, 16 Oct 2023 13:53:20 -0600 Subject: [PATCH 24/74] Move store_link into it's own method. --- .../src/Plugin/TripalStorage/ChadoStorage.php | 136 +++++++++++------- 1 file changed, 86 insertions(+), 50 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index 80ac7cf6f..6ad0b5b54 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -857,6 +857,9 @@ protected function buildChadoRecords($values, bool $is_store) { // Retrieve the operation to be used for searching and if not set, use equals as the default. $context['operation'] = array_key_exists('operation', $info) ? $info['operation'] : '='; + $context['field_name'] = $field_name; + $context['key'] = $key; + // Now for each action type, set the conditions and fields for // selecting chado records based on the other properties supplied. // ---------------------------------------------------------------- @@ -881,56 +884,7 @@ protected function buildChadoRecords($values, bool $is_store) { // in this property is the left_table_id indicated in other key/value pairs. // ................................................................ if ($action == 'store_link') { - // The old implementation of store_link used chado_table/column notation - // only for the right side of the relationship. - // This meant we could not reliably determine the left side of the - // relationship... Confirm this field uses the new method. - if (array_key_exists('right_table', $prop_storage_settings)) { - // Using the tables with a store_id, determine which side of this - // relationship is a base/core table. This will be used for the - // fields below to ensure the ID is replaced. - // Start by assuming the left table is the base/core table - // (e.g. feature.feature_id = featureprop.feature_id). - $link_base = $prop_storage_settings['left_table']; - $link_base_id = $prop_storage_settings['left_table_id']; - $linker = $prop_storage_settings['right_table']; - $linker_id = $prop_storage_settings['right_table_id']; - // Then check if the right table has a store_id and if so, use it instead. - // (e.g. analysisfeature.analysis_id = analysis.analysis_id) - if (array_key_exists($prop_storage_settings['right_table'], $context['base_record_ids'])) { - $link_base = $prop_storage_settings['right_table']; - $link_base_id = $prop_storage_settings['right_table_id']; - $linker = $prop_storage_settings['left_table']; - $linker_id = $prop_storage_settings['left_table_id']; - } - // @debug print "We decided it should be BASE $link_base.$link_base_id => LINKER $linker.$linker_id.\n"; - // We want to ensure that the linker table has a field added with - // the link to replace the ID once it's available. - $records[$linker] = $records[$linker] ?? [$delta => ['fields' => []]]; - $records[$linker][$delta] = $records[$linker][$delta] ?? ['fields' => []]; - $records[$linker][$delta]['fields'] = $records[$linker][$delta]['fields'] ?? []; - if (!array_key_exists($linker_id, $records[$linker][$delta]['fields'])) { - if ($prop_storage_settings['left_table'] !== NULL) { - $records[$linker][$delta]['fields'][$linker_id] = ['REPLACE_BASE_RECORD_ID', $link_base]; - // @debug print "Adding a note to replace $linker.$linker_id with $link_base record_id\n"; - } - } - } - else { - // Otherwise this field is using the old method for store_link. - // We will enter backwards compatibility mode here to do our best... - // It will work to handle CRUD for direct connections (e.g. props) - // but will cause problems with double-hops and all token replacement. - $bc_chado_table = $prop_storage_settings['chado_table']; - $bc_chado_column = $prop_storage_settings['chado_column']; - $records[$bc_chado_table][$delta]['fields'][$bc_chado_column] = ['REPLACE_BASE_RECORD_ID', $context['base_table']]; - $this->logger->warning( - 'We had to use backwards compatible mode for :name.:key property type with an action of store_link.' - .' Please update the code for this field to use left/right table notation for the store_link property.' - .' Backwards compatible mode should allow this field to save/load data but may result in errors with token replacement and publishing.', - [':name' => $field_name, ':key' => $key] - ); - } + $this->buildChadoRecords_store_link($records, $delta, $prop_storage_settings, $context, $prop_value); } // STORE: indicates that the value of this property can be loaded and // stored in the Chado table indicated by this property. @@ -1179,6 +1133,88 @@ protected function buildChadoRecords_store_pkey(array &$records, int $delta, arr } +/** + * Add chado record information for a specific ChadoStorageProperty + * where the action is store_link. + * + * STORE LINK: performs a join between two tables, one of which is a + * core table and one of which is a linking table. The value which is saved + * in this property is the left_table_id indicated in other key/value pairs. + * + * NOTE: A JOIN is not added to the query but rather this property stores + * the id that a join would normally look up. This is much more performant. + * + * @param array $records + * The current set of chado records. This method will update this array. + * @param int $delta + * The position in the values array the current property type stands + * and thus the position in the records array it should be. + * @param array $storage_settings + * The storage settings for the current property. This is all the information + * from the property type. + * @param array $context + * A set of values to provide context. These a pre-computed in the parent method + * to reduce code duplication when a task is done for all/many storage properties + * regardless of their action. + * @param StoragePropertyValue $prop_value + * The value object for the property we are adding records for. + * Note: We will always have a StoragePropertyValue for a property even if + * the value is not set. This method is expected to check if the value is empty or not. + */ + protected function buildChadoRecords_store_link(array &$records, int $delta, array $storage_settings, array &$context, StoragePropertyValue $prop_value) { + + // The old implementation of store_link used chado_table/column notation + // only for the right side of the relationship. + // This meant we could not reliably determine the left side of the + // relationship... Confirm this field uses the new method. + if (array_key_exists('right_table', $storage_settings)) { + // Using the tables with a store_id, determine which side of this + // relationship is a base/core table. This will be used for the + // fields below to ensure the ID is replaced. + // Start by assuming the left table is the base/core table + // (e.g. feature.feature_id = featureprop.feature_id). + $link_base = $storage_settings['left_table']; + $link_base_id = $storage_settings['left_table_id']; + $linker = $storage_settings['right_table']; + $linker_id = $storage_settings['right_table_id']; + // Then check if the right table has a store_id and if so, use it instead. + // (e.g. analysisfeature.analysis_id = analysis.analysis_id) + if (array_key_exists($storage_settings['right_table'], $context['base_record_ids'])) { + $link_base = $storage_settings['right_table']; + $link_base_id = $storage_settings['right_table_id']; + $linker = $storage_settings['left_table']; + $linker_id = $storage_settings['left_table_id']; + } + // @debug print "We decided it should be BASE $link_base.$link_base_id => LINKER $linker.$linker_id.\n"; + // We want to ensure that the linker table has a field added with + // the link to replace the ID once it's available. + $records[$linker] = $records[$linker] ?? [$delta => ['fields' => []]]; + $records[$linker][$delta] = $records[$linker][$delta] ?? ['fields' => []]; + $records[$linker][$delta]['fields'] = $records[$linker][$delta]['fields'] ?? []; + if (!array_key_exists($linker_id, $records[$linker][$delta]['fields'])) { + if ($storage_settings['left_table'] !== NULL) { + $records[$linker][$delta]['fields'][$linker_id] = ['REPLACE_BASE_RECORD_ID', $link_base]; + // @debug print "Adding a note to replace $linker.$linker_id with $link_base record_id\n"; + } + } + } + else { + // Otherwise this field is using the old method for store_link. + // We will enter backwards compatibility mode here to do our best... + // It will work to handle CRUD for direct connections (e.g. props) + // but will cause problems with double-hops and all token replacement. + $bc_chado_table = $storage_settings['chado_table']; + $bc_chado_column = $storage_settings['chado_column']; + $records[$bc_chado_table][$delta]['fields'][$bc_chado_column] = ['REPLACE_BASE_RECORD_ID', $context['base_table']]; + $this->logger->warning( + 'We had to use backwards compatible mode for :name.:key property type with an action of store_link.' + .' Please update the code for this field to use left/right table notation for the store_link property.' + .' Backwards compatible mode should allow this field to save/load data but may result in errors with token replacement and publishing.', + [':name' => $context['field_name'], ':key' => $context['key']] + ); + } + } + /** * * @param array $records From ea49aab2878753084141c4143d3bc8dd6fd05d89 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Mon, 16 Oct 2023 14:16:41 -0600 Subject: [PATCH 25/74] Move store into it's own method. --- .../src/Plugin/TripalStorage/ChadoStorage.php | 71 +++++++++++++++---- 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index 6ad0b5b54..21966c59d 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -890,19 +890,7 @@ protected function buildChadoRecords($values, bool $is_store) { // stored in the Chado table indicated by this property. // ................................................................ if ($action == 'store') { - $chado_column = $prop_storage_settings['chado_column']; - $value = $prop_value->getValue(); - if (is_string($value)) { - $value = trim($value); - } - $records[$chado_table][$delta]['fields'][$chado_column] = $value; - - // If this field should not allow an empty value that means this - // entire record should be removed on an update and not inserted. - $delete_if_empty = array_key_exists('delete_if_empty',$prop_storage_settings) ? $prop_storage_settings['delete_if_empty'] : FALSE; - if ($delete_if_empty) { - $records[$chado_table][$delta]['delete_if_empty'][] = $chado_column; - } + $this->buildChadoRecords_store($records, $delta, $prop_storage_settings, $context, $prop_value); } // READ_VALUE: selecting a single column. This cannot be used for inserting or // updating values. Instead we use store actions for that. @@ -1133,7 +1121,7 @@ protected function buildChadoRecords_store_pkey(array &$records, int $delta, arr } -/** + /** * Add chado record information for a specific ChadoStorageProperty * where the action is store_link. * @@ -1215,6 +1203,61 @@ protected function buildChadoRecords_store_link(array &$records, int $delta, arr } } +/** + * Add chado record information for a specific ChadoStorageProperty + * where the action is store. + * + * STORE: indicates that the value of this property can be loaded and + * stored in the Chado table indicated by this property. + * + * @param array $records + * The current set of chado records. This method will update this array. + * @param int $delta + * The position in the values array the current property type stands + * and thus the position in the records array it should be. + * @param array $storage_settings + * The storage settings for the current property. This is all the information + * from the property type. + * @param array $context + * A set of values to provide context. These a pre-computed in the parent method + * to reduce code duplication when a task is done for all/many storage properties + * regardless of their action. + * @param StoragePropertyValue $prop_value + * The value object for the property we are adding records for. + * Note: We will always have a StoragePropertyValue for a property even if + * the value is not set. This method is expected to check if the value is empty or not. + */ + protected function buildChadoRecords_store(array &$records, int $delta, array $storage_settings, array &$context, StoragePropertyValue $prop_value) { + + // Get the Chado table this specific property works with. + // Use the base table as a default for properties which do not specify + // the chado table (e.g. single value fields). + $chado_table = $context['base_table']; + if (array_key_exists('chado_table', $storage_settings)) { + $chado_table = $storage_settings['chado_table']; + } + // Now grab the column we are interested in. + $chado_column = $storage_settings['chado_column']; + + // Retrieve the value and clean it up. + $value = $prop_value->getValue(); + if (is_string($value)) { + $value = trim($value); + } + + $records[$chado_table][$delta]['fields'][$chado_column] = $value; + + // If this field should not allow an empty value that means this + // entire record should be removed on an update and not inserted. + $delete_if_empty = FALSE; + if (array_key_exists('delete_if_empty', $storage_settings)) { + $delete_if_empty = $storage_settings['delete_if_empty']; + } + if ($delete_if_empty) { + $records[$chado_table][$delta]['delete_if_empty'][] = $chado_column; + } + } + /** * * @param array $records From d1e13efbe397ff95a6146bd985c475018c78742b Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Mon, 16 Oct 2023 14:21:55 -0600 Subject: [PATCH 26/74] Move read_value into it's own method. --- .../src/Plugin/TripalStorage/ChadoStorage.php | 94 ++++++++++++++----- 1 file changed, 68 insertions(+), 26 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index 21966c59d..805d9eb13 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -898,31 +898,7 @@ protected function buildChadoRecords($values, bool $is_store) { // be provided. This also supports the deprecated 'join' action. // ................................................................ if (in_array($action, ['read_value', 'join'])) { - $chado_column = $prop_storage_settings['chado_column']; - // If a join is needed to access the column, then the 'path' needs - // to be defined and the joins need to be added to the query. - // This will also add the fields to be selected. - if (array_key_exists('path', $prop_storage_settings)) { - $path = $prop_storage_settings['path']; - $as = array_key_exists('as', $prop_storage_settings) ? $prop_storage_settings['as'] : $chado_column; - $path_arr = explode(";", $path); - $this->addChadoRecordJoins($records, $chado_column, $as, $delta, $path_arr); - } - // Otherwise, it is a column in a base table. In this case, we - // only need to ensure the column is added to the fields. - else { - // We will only set this if it's not already set. - // This is to allow another field with a store set for this column - // to set this value. We actually only do this to ensure it ends up - // in the query fields. - if (!array_key_exists('fields', $records[$chado_table][$delta])) { - $records[$chado_table][$delta]['fields'] = []; - $records[$chado_table][$delta]['fields'][$chado_column] = NULL; - } - elseif (!array_key_exists($chado_column, $records[$chado_table][$delta]['fields'])) { - $records[$chado_table][$delta]['fields'][$chado_column] = NULL; - } - } + $this->buildChadoRecords_read_value($records, $delta, $prop_storage_settings, $context, $prop_value); } // REPLACE: replace a tokenized string with the values from other // properties. As such we do not need to worry about adding this @@ -1203,7 +1179,7 @@ protected function buildChadoRecords_store_link(array &$records, int $delta, arr } } -/** + /** * Add chado record information for a specific ChadoStorageProperty * where the action is store. * @@ -1258,6 +1234,72 @@ protected function buildChadoRecords_store(array &$records, int $delta, array $s } } + /** + * Add chado record information for a specific ChadoStorageProperty + * where the action is read_value. + * + * READ_VALUE: selecting a single column. This cannot be used for inserting or + * updating values. Instead we use store actions for that. + * If reading a value from a non-base table, then the path should + * be provided. + * + * This also supports the deprecated 'join' action. + * + * @param array $records + * The current set of chado records. This method will update this array. + * @param int $delta + * The position in the values array the current property type stands + * and thus the position in the records array it should be. + * @param array $storage_settings + * The storage settings for the current property. This is all the information + * from the property type. + * @param array $context + * A set of values to provide context. These a pre-computed in the parent method + * to reduce code duplication when a task is done for all/many storage properties + * regardless of their action. + * @param StoragePropertyValue $prop_value + * The value object for the property we are adding records for. + * Note: We will always have a StoragePropertyValue for a property even if + * the value is not set. This method is expected to check if the value is empty or not. + */ + protected function buildChadoRecords_read_value(array &$records, int $delta, array $storage_settings, array &$context, StoragePropertyValue $prop_value) { + + // Get the Chado table this specific property works with. + // Use the base table as a default for properties which do not specify + // the chado table (e.g. single value fields). + $chado_table = $context['base_table']; + if (array_key_exists('chado_table', $storage_settings)) { + $chado_table = $storage_settings['chado_table']; + } + + $chado_column = $storage_settings['chado_column']; + + // If a join is needed to access the column, then the 'path' needs + // to be defined and the joins need to be added to the query. + // This will also add the fields to be selected. + if (array_key_exists('path', $storage_settings)) { + $path = $storage_settings['path']; + $as = array_key_exists('as', $storage_settings) ? $storage_settings['as'] : $chado_column; + $path_arr = explode(";", $path); + $this->addChadoRecordJoins($records, $chado_column, $as, $delta, $path_arr); + } + // Otherwise, it is a column in a base table. In this case, we + // only need to ensure the column is added to the fields. + else { + // We will only set this if it's not already set. + // This is to allow another field with a store set for this column + // to set this value. We actually only do this to ensure it ends up + // in the query fields. + if (!array_key_exists('fields', $records[$chado_table][$delta])) { + $records[$chado_table][$delta]['fields'] = []; + $records[$chado_table][$delta]['fields'][$chado_column] = NULL; + } + elseif (!array_key_exists($chado_column, $records[$chado_table][$delta]['fields'])) { + $records[$chado_table][$delta]['fields'][$chado_column] = NULL; + } + } + } + /** * * @param array $records From 7053bd4385a22c2956bc2dbeb657dca029f79d4b Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Mon, 16 Oct 2023 14:33:44 -0600 Subject: [PATCH 27/74] Switch to a switch instead of all the if statements. --- .../src/Plugin/TripalStorage/ChadoStorage.php | 76 +++++++------------ 1 file changed, 26 insertions(+), 50 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index 805d9eb13..33d5610a7 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -863,56 +863,32 @@ protected function buildChadoRecords($values, bool $is_store) { // Now for each action type, set the conditions and fields for // selecting chado records based on the other properties supplied. // ---------------------------------------------------------------- - // STORE ID: stores the primary key value for a core table in chado - // Note: There may be more core tables in properties for this field - // then just the base table. For example, a field involving a two-join - // linker table will include two core tables. - // ................................................................ - if ($action == 'store_id') { - $this->buildChadoRecords_store_id($records, $delta, $prop_storage_settings, $context, $prop_value); - } - // STORE PKEY: stores the primary key value of a linking table. - // NOTE: A linking table is not a core table. This is important because - // during insert and update, the core tables are handled first and then - // linking tables are handled after. - // ................................................................ - if ($action == 'store_pkey') { - $this->buildChadoRecords_store_pkey($records, $delta, $prop_storage_settings, $context, $prop_value); - } - // STORE LINK: performs a join between two tables, one of which is a - // core table and one of which is a linking table. The value which is saved - // in this property is the left_table_id indicated in other key/value pairs. - // ................................................................ - if ($action == 'store_link') { - $this->buildChadoRecords_store_link($records, $delta, $prop_storage_settings, $context, $prop_value); - } - // STORE: indicates that the value of this property can be loaded and - // stored in the Chado table indicated by this property. - // ................................................................ - if ($action == 'store') { - $this->buildChadoRecords_store($records, $delta, $prop_storage_settings, $context, $prop_value); - } - // READ_VALUE: selecting a single column. This cannot be used for inserting or - // updating values. Instead we use store actions for that. - // If reading a value from a non-base table, then the path should - // be provided. This also supports the deprecated 'join' action. - // ................................................................ - if (in_array($action, ['read_value', 'join'])) { - $this->buildChadoRecords_read_value($records, $delta, $prop_storage_settings, $context, $prop_value); - } - // REPLACE: replace a tokenized string with the values from other - // properties. As such we do not need to worry about adding this - // property to the chado queries. - // ................................................................ - if ($action == 'replace') { - // Do nothing here for properties that need replacement. - } - // FUNCTION: use a function to determine the value of this property. - // As such, we do not need to add this property to the chado queries. - // ................................................................ - if ($action == 'function') { - // Do nothing here for properties that require post-processing - // with a function. + switch ($action) { + case 'store_id': + $this->buildChadoRecords_store_id($records, $delta, $prop_storage_settings, $context, $prop_value); + break; + case 'store_pkey': + $this->buildChadoRecords_store_pkey($records, $delta, $prop_storage_settings, $context, $prop_value); + break; + case 'store_link': + $this->buildChadoRecords_store_link($records, $delta, $prop_storage_settings, $context, $prop_value); + break; + case 'store': + $this->buildChadoRecords_store($records, $delta, $prop_storage_settings, $context, $prop_value); + break; + case 'read_value': + case 'join': + $this->buildChadoRecords_read_value($records, $delta, $prop_storage_settings, $context, $prop_value); + break; + case 'replace': + // Do nothing here for properties that need replacement + // since the values are provided by other properties. + break; + case 'function': + // Do nothing here for properties that require post-processing + // with a function as determining the value is handled by + // the function not by chadostorage. + break; } } } From 33f0bfa3579a70d663ae6e1d0f7abf508cd25c77 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Mon, 16 Oct 2023 17:12:56 -0600 Subject: [PATCH 28/74] Working towards using table alias' in the prop field. --- .../FieldType/ChadoLinkerPropertyDefault.php | 20 ++++- .../src/Plugin/TripalStorage/ChadoStorage.php | 73 ++++++++++++++----- .../ChadoLinkerPropertyDefaultTest.php | 7 +- 3 files changed, 78 insertions(+), 22 deletions(-) diff --git a/tripal_chado/src/Plugin/Field/FieldType/ChadoLinkerPropertyDefault.php b/tripal_chado/src/Plugin/Field/FieldType/ChadoLinkerPropertyDefault.php index d3ff99095..b5d71354b 100644 --- a/tripal_chado/src/Plugin/Field/FieldType/ChadoLinkerPropertyDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldType/ChadoLinkerPropertyDefault.php @@ -77,6 +77,15 @@ public static function tripalTypes($field_definition) { $rank_term = $mapping->getColumnTermId($prop_table, 'rank'); $type_id_term = $mapping->getColumnTermId($prop_table, 'type_id'); + // We need to create a table alias for our prop table in order to ensure + // values of other property types are not combined. + // The type used when creating the prop record will be the same as the + // type set for the field. As such, we grab that here and use it in our + // table alias. + $field_settings = $field_definition->getSettings(); + $term = $field_settings['termIdSpace'] . ': ' . $field_settings['termAccession']; + $table_alias = $prop_table . '_' . preg_replace( '/[^a-z0-9]+/', '', strtolower( $term ) ); + // Create the property types. return [ new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'record_id', $record_id_term, [ @@ -90,15 +99,20 @@ public static function tripalTypes($field_definition) { 'drupal_store' => TRUE, 'chado_table' => $prop_table, 'chado_column' => $prop_pkey_col, + 'chado_table_alias' => $table_alias, ]), new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'linker_id', $link_term, [ 'action' => 'store_link', - 'chado_table' => $prop_table, - 'chado_column' => $prop_fk_col, + 'left_table' => $base_table, + 'left_table_id' => $base_pkey_col, + 'right_table' => $prop_table, + 'right_table_alias' => $table_alias, + 'right_table_id' => $prop_fk_col, ]), new ChadoTextStoragePropertyType($entity_type_id, self::$id, 'value', $value_term, [ 'action' => 'store', 'chado_table' => $prop_table, + 'chado_table_alias' => $table_alias, 'chado_column' => 'value', 'delete_if_empty' => TRUE, 'empty_value' => '' @@ -106,11 +120,13 @@ public static function tripalTypes($field_definition) { new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'rank', $rank_term, [ 'action' => 'store', 'chado_table' => $prop_table, + 'chado_table_alias' => $table_alias, 'chado_column' => 'rank' ]), new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'type_id', $type_id_term, [ 'action' => 'store', 'chado_table' => $prop_table, + 'chado_table_alias' => $table_alias, 'chado_column' => 'type_id' ]), ]; diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index 33d5610a7..e78a836d5 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -991,6 +991,13 @@ protected function buildChadoRecords_store_id(array &$records, int $delta, array $chado_table_def = $this->connection->schema()->getTableDef($chado_table, ['format' => 'drupal']); $chado_table_pkey = $chado_table_def['primary key']; + // Check if there is a table alias set and if so, then use it. + $table_alias = $chado_table; + if (array_key_exists('chado_table_alias', $storage_settings)) { + $table_alias = $storage_settings['chado_table_alias']; + $context['table_alias'][$table_alias] = $chado_table; + } + // Get the value if it is set. $record_id = $prop_value->getValue(); @@ -998,7 +1005,7 @@ protected function buildChadoRecords_store_id(array &$records, int $delta, array // this property. Let's set it to be replaced in the hopes that // some other property has already been inserted and has the ID. if ($record_id == 0) { - $records[$chado_table][0]['conditions'][$chado_table_pkey] = [ + $records[$table_alias][0]['conditions'][$chado_table_pkey] = [ 'value' => [ 'REPLACE_BASE_RECORD_ID', $context['base_table'] @@ -1015,12 +1022,12 @@ protected function buildChadoRecords_store_id(array &$records, int $delta, array // then we want to set it here and add it to the array of core ids // for use later when replacing base record ids. else { - $records[$chado_table][0]['conditions'][$chado_table_pkey] = [ + $records[$table_alias][0]['conditions'][$chado_table_pkey] = [ 'value' => $record_id, 'operation' => $context['operation'] ]; - $context['base_record_ids'][$chado_table] = $record_id; + $context['base_record_ids'][$table_alias] = $record_id; } } @@ -1064,9 +1071,16 @@ protected function buildChadoRecords_store_pkey(array &$records, int $delta, arr $chado_table_def = $this->connection->schema()->getTableDef($chado_table, ['format' => 'drupal']); $chado_table_pkey = $chado_table_def['primary key']; + // Check if there is a table alias set and if so, then use it. + $table_alias = $chado_table; + if (array_key_exists('chado_table_alias', $storage_settings)) { + $table_alias = $storage_settings['chado_table_alias']; + $context['table_alias'][$table_alias] = $chado_table; + } + $link_record_id = $prop_value->getValue(); - $records[$chado_table][$delta]['conditions'][$chado_table_pkey] = [ + $records[$table_alias][$delta]['conditions'][$chado_table_pkey] = [ 'value' => $link_record_id, 'operation' => $context['operation'] ]; @@ -1117,6 +1131,7 @@ protected function buildChadoRecords_store_link(array &$records, int $delta, arr $link_base_id = $storage_settings['left_table_id']; $linker = $storage_settings['right_table']; $linker_id = $storage_settings['right_table_id']; + $linker_alias = (array_key_exists('right_table_alias', $storage_settings)) ? $storage_settings['right_table_alias'] : $linker; // Then check if the right table has a store_id and if so, use it instead. // (e.g. analysisfeature.analysis_id = analysis.analysis_id) if (array_key_exists($storage_settings['right_table'], $context['base_record_ids'])) { @@ -1124,18 +1139,23 @@ protected function buildChadoRecords_store_link(array &$records, int $delta, arr $link_base_id = $storage_settings['right_table_id']; $linker = $storage_settings['left_table']; $linker_id = $storage_settings['left_table_id']; + $linker_alias = (array_key_exists('left_table_alias', $storage_settings)) ? $storage_settings['left_table_alias'] : $linker; } + + // If an alias was set then make sure it's added to the context. + if ($linker_alias != $linker) { + $context['table_alias'][$linker_alias] = $linker; + } + // @debug print "We decided it should be BASE $link_base.$link_base_id => LINKER $linker.$linker_id.\n"; // We want to ensure that the linker table has a field added with // the link to replace the ID once it's available. - $records[$linker] = $records[$linker] ?? [$delta => ['fields' => []]]; - $records[$linker][$delta] = $records[$linker][$delta] ?? ['fields' => []]; - $records[$linker][$delta]['fields'] = $records[$linker][$delta]['fields'] ?? []; - if (!array_key_exists($linker_id, $records[$linker][$delta]['fields'])) { - if ($storage_settings['left_table'] !== NULL) { - $records[$linker][$delta]['fields'][$linker_id] = ['REPLACE_BASE_RECORD_ID', $link_base]; - // @debug print "Adding a note to replace $linker.$linker_id with $link_base record_id\n"; - } + $records[$linker_alias] = $records[$linker_alias] ?? [$delta => ['fields' => []]]; + $records[$linker_alias][$delta] = $records[$linker_alias][$delta] ?? ['fields' => []]; + $records[$linker_alias][$delta]['fields'] = $records[$linker_alias][$delta]['fields'] ?? []; + if (!array_key_exists($linker_id, $records[$linker_alias][$delta]['fields'])) { + $records[$linker_alias][$delta]['fields'][$linker_id] = ['REPLACE_BASE_RECORD_ID', $link_base]; + // @debug print "Adding a note to replace $linker.$linker_id with $link_base record_id\n"; } } else { @@ -1188,6 +1208,14 @@ protected function buildChadoRecords_store(array &$records, int $delta, array $s if (array_key_exists('chado_table', $storage_settings)) { $chado_table = $storage_settings['chado_table']; } + + // Check if there is a table alias set and if so, then use it. + $table_alias = $chado_table; + if (array_key_exists('chado_table_alias', $storage_settings)) { + $table_alias = $storage_settings['chado_table_alias']; + $context['table_alias'][$table_alias] = $chado_table; + } + // Now grab the column we are interested in. $chado_column = $storage_settings['chado_column']; @@ -1197,7 +1225,7 @@ protected function buildChadoRecords_store(array &$records, int $delta, array $s $value = trim($value); } - $records[$chado_table][$delta]['fields'][$chado_column] = $value; + $records[$table_alias][$delta]['fields'][$chado_column] = $value; // If this field should not allow an empty value that means this // entire record should be removed on an update and not inserted. @@ -1206,7 +1234,7 @@ protected function buildChadoRecords_store(array &$records, int $delta, array $s $delete_if_empty = $storage_settings['delete_if_empty']; } if ($delete_if_empty) { - $records[$chado_table][$delta]['delete_if_empty'][] = $chado_column; + $records[$table_alias][$delta]['delete_if_empty'][] = $chado_column; } } @@ -1248,6 +1276,13 @@ protected function buildChadoRecords_read_value(array &$records, int $delta, arr $chado_table = $storage_settings['chado_table']; } + // Check if there is a table alias set and if so, then use it. + $table_alias = $chado_table; + if (array_key_exists('chado_table_alias', $storage_settings)) { + $table_alias = $storage_settings['chado_table_alias']; + $context['table_alias'][$table_alias] = $chado_table; + } + $chado_column = $storage_settings['chado_column']; // If a join is needed to access the column, then the 'path' needs @@ -1266,12 +1301,12 @@ protected function buildChadoRecords_read_value(array &$records, int $delta, arr // This is to allow another field with a store set for this column // to set this value. We actually only do this to ensure it ends up // in the query fields. - if (!array_key_exists('fields', $records[$chado_table][$delta])) { - $records[$chado_table][$delta]['fields'] = []; - $records[$chado_table][$delta]['fields'][$chado_column] = NULL; + if (!array_key_exists('fields', $records[$table_alias][$delta])) { + $records[$table_alias][$delta]['fields'] = []; + $records[$table_alias][$delta]['fields'][$chado_column] = NULL; } - elseif (!array_key_exists($chado_column, $records[$chado_table][$delta]['fields'])) { - $records[$chado_table][$delta]['fields'][$chado_column] = NULL; + elseif (!array_key_exists($chado_column, $records[$table_alias][$delta]['fields'])) { + $records[$table_alias][$delta]['fields'][$chado_column] = NULL; } } } diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php index 12f5f2a32..4fd1eb769 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php @@ -58,6 +58,7 @@ class ChadoLinkerPropertyDefaultTest extends ChadoTestKernelBase { 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store_pkey', 'chado_table' => 'featureprop', + 'chado_table_alias' => 'featureprop_rdfstype', 'chado_column' => 'featureprop_id', ], // Generate `JOIN {featureprop} ON feature.feature_id = featureprop.feature_id` @@ -68,6 +69,7 @@ class ChadoLinkerPropertyDefaultTest extends ChadoTestKernelBase { 'left_table' => 'feature', 'left_table_id' => 'feature_id', 'right_table' => 'featureprop', + 'right_table_alias' => 'featureprop_rdfstype', 'right_table_id' => 'feature_id' ], // Now we are going to store all the core columns of the featureprop table to @@ -76,12 +78,14 @@ class ChadoLinkerPropertyDefaultTest extends ChadoTestKernelBase { 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store', 'chado_table' => 'featureprop', + 'chado_table_alias' => 'featureprop_rdfstype', 'chado_column' => 'type_id' ], 'A_value' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoTextStoragePropertyType', 'action' => 'store', 'chado_table' => 'featureprop', + 'chado_table_alias' => 'featureprop_rdfstype', 'chado_column' => 'value', 'delete_if_empty' => TRUE, 'empty_value' => '' @@ -90,6 +94,7 @@ class ChadoLinkerPropertyDefaultTest extends ChadoTestKernelBase { 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store', 'chado_table' => 'featureprop', + 'chado_table_alias' => 'featureprop_rdfstype', 'chado_column' => 'rank' ], ], @@ -274,7 +279,7 @@ public function provideSinglePropFieldNames() { * - [NOT IMPLEMENTED] Delete values in Chado using ChadoStorage. * - [NOT IMPLEMENTED] Ensure property field picks up records in Chado not added through field. */ - public function testInsertValuesForSingleField($prop_field_name) { + public function testCRUDForSinglePropField($prop_field_name) { $rdfs_comment_cvtermID = $this->getCvtermID('rdfs', 'comment'); $gene_cvtermID = $this->getCvtermID('SO', '0000704'); From cef58459e8f2540fef1ea4fc809b84d2ac3161a7 Mon Sep 17 00:00:00 2001 From: Malladi Date: Tue, 17 Oct 2023 20:11:48 -0500 Subject: [PATCH 29/74] Tripal 4 tripal collections YAML file and Sequence Length and Checksum fields in : tv4g1-1509-sequence-fields --- ...l.tripalfield_collection.default_chado.yml | 169 ++++++++++++++++-- .../ChadoSequenceChecksumDefault.php | 4 +- .../FieldType/ChadoSequenceLengthDefault.php | 2 +- 3 files changed, 153 insertions(+), 22 deletions(-) diff --git a/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml b/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml index 060ab621a..edc866297 100644 --- a/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml +++ b/tripal_chado/config/install/tripal.tripalfield_collection.default_chado.yml @@ -1069,8 +1069,8 @@ fields: - name: mrna_sequence content_type: mRNA - label: Sequence - type: chado_text_type + label: Sequence Residues + type: chado_sequence_default description: One or more molecular sequences, possibly with associated annotation. cardinality: 1 required: false @@ -1096,7 +1096,7 @@ fields: - name: mrna_sequence_length content_type: mRNA label: Sequence Length - type: chado_integer_type + type: chado_sequence_length_default description: The size (length) of a sequence, subsequence or region in a sequence, or range(s) of lengths. cardinality: 1 required: false @@ -1119,6 +1119,32 @@ fields: region: content weight: 25 + - name: mrna_sequence_md5_checksum + content_type: mRNA + label: Sequence MD5 Checksum + type: chado_sequence_checksum_default + description: The 32-character checksum of the sequence, calculated using the MD5 algorithm. + cardinality: 1 + required: false + storage_settings: + storage_plugin_id: chado_storage + storage_plugin_settings: + base_table: feature + base_column: md5checksum + settings: + termIdSpace: data + termAccession: "2190" + display: + view: + default: + region: content + label: above + weight: 30 + form: + default: + region: content + weight: 30 + - name: mrna_organism content_type: mRNA label: Organism @@ -2168,7 +2194,7 @@ fields: - name: qtl_unique_name content_type: QTL - label: Uniquen Name + label: Unique Name type: chado_text_type description: A name that uniquely identifies the QTL within the organism. cardinality: 1 @@ -2194,8 +2220,8 @@ fields: - name: qtl_sequence content_type: QTL - label: Sequence - type: chado_text_type + label: Sequence Residues + type: chado_sequence_default description: One or more molecular sequences, possibly with associated annotation. cardinality: 1 required: false @@ -2221,7 +2247,7 @@ fields: - name: qtl_sequence_length content_type: QTL label: Sequence Length - type: chado_integer_type + type: chado_sequence_length_default description: The size (length) of a sequence, subsequence or region in a sequence, or range(s) of lengths. cardinality: 1 required: false @@ -2244,6 +2270,33 @@ fields: region: content weight: 25 + - name: qtl_md5_checksum + content_type: QTL + label: Sequence MD5 Checksum + type: chado_sequence_checksum_default + description: The 32-character checksum of the sequence, calculated using the MD5 algorithm. + cardinality: 1 + required: false + storage_settings: + storage_plugin_id: chado_storage + storage_plugin_settings: + base_table: feature + base_column: md5checksum + settings: + termIdSpace: data + termAccession: "2190" + display: + view: + default: + region: content + label: above + weight: 30 + form: + default: + region: content + weight: 30 + + - name: qtl_organism content_type: QTL label: Organism @@ -2379,7 +2432,7 @@ fields: region: content weight: 10 - - name: sequence_variant_uniquene_name + - name: sequence_variant_unique_name content_type: sequence_variant label: Unique Name type: chado_text_type @@ -2407,8 +2460,8 @@ fields: - name: sequence_variant_sequence content_type: sequence_variant - label: Sequence - type: chado_text_type + label: Sequence Residues + type: chado_sequence_default description: One or more molecular sequences, possibly with associated annotation. cardinality: 1 required: false @@ -2434,7 +2487,7 @@ fields: - name: sequence_variant_sequence_length content_type: sequence_variant label: Sequence Length - type: chado_integer_type + type: chado_sequence_length_default description: The size (length) of a sequence, subsequence or region in a sequence, or range(s) of lengths. cardinality: 1 required: false @@ -2457,6 +2510,32 @@ fields: region: content weight: 25 + - name: sequence_variant_md5_checksum + content_type: sequence_variant + label: Sequence MD5 Checksum + type: chado_sequence_checksum_default + description: The 32-character checksum of the sequence, calculated using the MD5 algorithm. + cardinality: 1 + required: false + storage_settings: + storage_plugin_id: chado_storage + storage_plugin_settings: + base_table: feature + base_column: md5checksum + settings: + termIdSpace: data + termAccession: "2190" + display: + view: + default: + region: content + label: above + weight: 30 + form: + default: + region: content + weight: 30 + - name: sequence_variant_organism content_type: sequence_variant label: Organism @@ -2620,8 +2699,8 @@ fields: - name: genetic_marker_sequence content_type: genetic_marker - label: Sequence - type: chado_text_type + label: Sequence Residues + type: chado_sequence_default description: One or more molecular sequences, possibly with associated annotation. cardinality: 1 required: false @@ -2647,7 +2726,7 @@ fields: - name: genetic_marker_sequence_length content_type: genetic_marker label: Sequence Length - type: chado_integer_type + type: chado_sequence_length_default description: The size (length) of a sequence, subsequence or region in a sequence,or range(s) of lengths. cardinality: 1 required: false @@ -2670,6 +2749,32 @@ fields: region: content weight: 25 + - name: genetic_marker_md5_checksum + content_type: genetic_marker + label: Sequence MD5 Checksum + type: chado_sequence_checksum_default + description: The 32-character checksum of the sequence, calculated using the MD5 algorithm. + cardinality: 1 + required: false + storage_settings: + storage_plugin_id: chado_storage + storage_plugin_settings: + base_table: feature + base_column: md5checksum + settings: + termIdSpace: data + termAccession: "2190" + display: + view: + default: + region: content + label: above + weight: 30 + form: + default: + region: content + weight: 30 + - name: genetic_marker_organism content_type: genetic_marker label: Organism @@ -2807,7 +2912,7 @@ fields: - name: phenotypic_marker_unique_name content_type: phenotypic_marker - label: Uniquen Name + label: Unique Name type: chado_text_type description: A name that uniquely identifies the heritable phenotypic marker within the organism. cardinality: 1 @@ -2833,8 +2938,8 @@ fields: - name: phenotypic_marker_sequence content_type: phenotypic_marker - label: Sequence - type: chado_text_type + label: Sequence Residues + type: chado_sequence_default description: One or more molecular sequences, possibly with associated annotation. cardinality: 1 required: false @@ -2857,10 +2962,10 @@ fields: region: content weight: 20 - - name: phenotypic_marker_seqlen + - name: phenotypic_marker_length content_type: phenotypic_marker label: Sequence Length - type: chado_integer_type + type: chado_sequence_length_default description: The size (length) of a sequence, subsequence or region in a sequence, or range(s) of lengths. cardinality: 1 required: false @@ -2883,6 +2988,32 @@ fields: region: content weight: 25 + - name: phenotypic_marker_md5_checksum + content_type: phenotypic_marker + label: Sequence MD5 Checksum + type: chado_sequence_checksum_default + description: The 32-character checksum of the sequence, calculated using the MD5 algorithm. + cardinality: 1 + required: false + storage_settings: + storage_plugin_id: chado_storage + storage_plugin_settings: + base_table: feature + base_column: md5checksum + settings: + termIdSpace: data + termAccession: "2190" + display: + view: + default: + region: content + label: above + weight: 30 + form: + default: + region: content + weight: 30 + - name: phenotypic_marker_organism content_type: phenotypic_marker label: Organism diff --git a/tripal_chado/src/Plugin/Field/FieldType/ChadoSequenceChecksumDefault.php b/tripal_chado/src/Plugin/Field/FieldType/ChadoSequenceChecksumDefault.php index de2b082fb..7b4896beb 100644 --- a/tripal_chado/src/Plugin/Field/FieldType/ChadoSequenceChecksumDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldType/ChadoSequenceChecksumDefault.php @@ -79,12 +79,12 @@ public static function tripalTypes($field_definition) { 'chado_column' => 'feature_id' ]); $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'seqlen', $seqlen_term, [ - 'action' => 'store', + 'action' => 'read_value', 'chado_column' => 'seqlen', 'chado_table' => 'feature' ]); $properties[] = new ChadoBpCharStoragePropertyType($entity_type_id, self::$id, 'md5checksum', $md5checksum_term, $md5_checksum_len, [ - 'action' => 'store', + 'action' => 'read_value', 'chado_column' => 'md5checksum', 'chado_table' => 'feature' ]); diff --git a/tripal_chado/src/Plugin/Field/FieldType/ChadoSequenceLengthDefault.php b/tripal_chado/src/Plugin/Field/FieldType/ChadoSequenceLengthDefault.php index 3463716b5..240c83a2b 100644 --- a/tripal_chado/src/Plugin/Field/FieldType/ChadoSequenceLengthDefault.php +++ b/tripal_chado/src/Plugin/Field/FieldType/ChadoSequenceLengthDefault.php @@ -73,7 +73,7 @@ public static function tripalTypes($field_definition) { 'chado_column' => 'feature_id' ]); $properties[] = new ChadoIntStoragePropertyType($entity_type_id, self::$id, 'seqlen', $seqlen_term, [ - 'action' => 'store', + 'action' => 'read_value', 'chado_column' => 'seqlen', 'chado_table' => 'feature' ]); From e064a355fd436d92eb0d92c1c7d6cd156eb4f014 Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 18 Oct 2023 15:53:42 -0600 Subject: [PATCH 30/74] Update insertChadoRecord() to be alias aware and add accessory variables + functions to support alias' --- .../src/Plugin/TripalStorage/ChadoStorage.php | 205 ++++++++++++++---- 1 file changed, 161 insertions(+), 44 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index e78a836d5..c0da1fe91 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -57,6 +57,39 @@ class ChadoStorage extends TripalStorageBase implements TripalStorageInterface { */ protected $field_debugger; + /** + * A collection of the primary key values for various base tables. + * + * This is populated as records are loaded/inserted and then used to later + * update foreign key values for dependant tables. + * + * @var array + * key is the table alias and value is the primary key value for the + * record with that table alias. If the ID is not yet known then the + * value is NULL. + */ + protected $base_record_ids = []; + + /** + * A mapping of table alias to chado table name. + * + * In most cases the table alias will be the same as the table name. However, + * especially in cases of chado prop and linking tables, an alias ensures that + * multiple fields can control a subset of records without interferance or + * data-swapping between fields. + * + * @var array + * key is the table alias and value is the official chado table name that + * the alias refers to. + */ + protected $table_alias_mapping = []; + + /** + * A mapping of the chado table to it's alias. This uses the field and property + * to ensure the alias is looked up properly. + */ + protected $reverse_alias_mapping = []; + /** * Implements ContainerFactoryPluginInterface->create(). * @@ -122,14 +155,17 @@ public function addFieldDefinition(string $field_name, object $field_definition) /** * Inserts a single record in a Chado table. + * * @param array $records - * @param string $chado_table + * @param string $chado_table_alias * @param integer $delta * @param array $record * @throws \Exception * @return integer */ - private function insertChadoRecord(&$records, $chado_table, $delta, $record) { + private function insertChadoRecord(&$records, $chado_table_alias, $delta, $record) { + + $chado_table = $this->getChadoTableFromAlias($chado_table_alias); $schema = $this->connection->schema(); $table_def = $schema->getTableDef($chado_table, ['format' => 'drupal']); @@ -144,12 +180,12 @@ private function insertChadoRecord(&$records, $chado_table, $delta, $record) { $record_id = $insert->execute(); if (!$record_id) { - throw new \Exception($this->t('Failed to insert a record in the Chado "@table" table. Record: @record', - ['@table' => $chado_table, '@record' => print_r($record, TRUE)])); + throw new \Exception($this->t('Failed to insert a record in the Chado "@table" table. Alias: @alias, Record: @record', + ['@alias' => $chado_table_alias, '@table' => $chado_table, '@record' => print_r($record, TRUE)])); } // Update the record array to include the record id. - $records[$chado_table][$delta]['conditions'][$pkey]['value'] = $record_id; + $records[$chado_table_alias][$delta]['conditions'][$pkey]['value'] = $record_id; return $record_id; } @@ -170,10 +206,10 @@ public function insertValues(&$values) : bool { try { // First: Insert the base table records. - foreach ($build['base_tables'] as $base_table => $record_id) { + foreach ($this->base_record_ids as $base_table => $record_id) { foreach ($records[$base_table] as $delta => $record) { $record_id = $this->insertChadoRecord($records, $base_table, $delta, $record); - $build['base_tables'][$base_table] = $record_id; + $this->base_record_ids[$base_table] = $record_id; } } @@ -182,7 +218,7 @@ public function insertValues(&$values) : bool { foreach ($deltas as $delta => $record) { // Skip base table records. - if (in_array($chado_table, array_keys($build['base_tables']))) { + if (in_array($chado_table, array_keys($this->base_record_ids))) { continue; } @@ -204,8 +240,8 @@ public function insertValues(&$values) : bool { foreach ($record['fields'] as $column => $val) { if (is_array($val) and $val[0] == 'REPLACE_BASE_RECORD_ID') { $base_table = $val[1]; - $records[$chado_table][$delta]['fields'][$column] = $build['base_tables'][$base_table]; - $record['fields'][$column] = $build['base_tables'][$base_table]; + $records[$chado_table][$delta]['fields'][$column] = $this->base_record_ids[$base_table]; + $record['fields'][$column] = $this->base_record_ids[$base_table]; } } $this->insertChadoRecord($records, $chado_table, $delta, $record); @@ -312,7 +348,7 @@ public function updateValues(&$values) : bool { $build = $this->buildChadoRecords($values, TRUE); $records = $build['records']; - $base_tables = $build['base_tables']; + $base_tables = $this->base_record_ids; $transaction_chado = $this->connection->startTransaction(); try { @@ -455,7 +491,7 @@ public function loadValues(&$values) : bool { $build = $this->buildChadoRecords($values, FALSE); $records = $build['records']; - $base_tables = $build['base_tables']; + $base_tables = $this->base_record_ids; $transaction_chado = $this->connection->startTransaction(); try { @@ -600,7 +636,7 @@ protected function setRecordIds(&$values, $records) { // If this is the record_id property then set its value. if ($action == 'store_id') { - $record_id = $records[$chado_table][0]['conditions'][$base_table_pkey]['value']; + $record_id = $records[$chado_table][0]['conditions'][$chado_table_pkey]['value']; $values[$field_name][$delta][$key]['value']->setValue($record_id); } // If this is the linked record_id property then set its value. @@ -610,6 +646,8 @@ protected function setRecordIds(&$values, $records) { } // If this is a property managing a linked record ID then set it too. if ($action == 'store_link') { + // @todo we should use left/right here rather than assuming there is + // only a single base table. $record_id = $records[$base_table][0]['conditions'][$base_table_pkey]['value']; $values[$field_name][$delta][$key]['value']->setValue($record_id); } @@ -796,12 +834,6 @@ protected function buildChadoRecords($values, bool $is_store) { $this->field_debugger->reportValues($values, 'The values submitted to ChadoStorage'); - // Define an array containing context information that will be used - // for all the actions. - $context = [ - 'base_record_ids' => [], - ]; - // Iterate through the value objects. foreach ($values as $field_name => $deltas) { @@ -858,7 +890,7 @@ protected function buildChadoRecords($values, bool $is_store) { $context['operation'] = array_key_exists('operation', $info) ? $info['operation'] : '='; $context['field_name'] = $field_name; - $context['key'] = $key; + $context['property_key'] = $key; // Now for each action type, set the conditions and fields for // selecting chado records based on the other properties supplied. @@ -909,14 +941,14 @@ protected function buildChadoRecords($values, bool $is_store) { // If the core table is set in the base record ids array and the // value is not 0 then we can set this chado field now! - if (array_key_exists($core_table, $context['base_record_ids']) and $context['base_record_ids'][$core_table] != 0) { - $records[$table_name][$delta]['fields'][$chado_column] = $context['base_record_ids'][$core_table]; + if (array_key_exists($core_table, $this->base_record_ids) and $this->base_record_ids[$core_table] != 0) { + $records[$table_name][$delta]['fields'][$chado_column] = $this->base_record_ids[$core_table]; } // If the base record ID is 0 then this is an insert and we // don't yet have the base record ID. So, leave in the message // to replace the ID so we can do so later. - if (array_key_exists($base_table, $context['base_record_ids']) and $context['base_record_ids'][$base_table] != 0) { - $records[$table_name][$delta]['fields'][$chado_column] = $context['base_record_ids'][$base_table]; + if (array_key_exists($base_table, $this->base_record_ids) and $this->base_record_ids[$base_table] != 0) { + $records[$table_name][$delta]['fields'][$chado_column] = $this->base_record_ids[$base_table]; } } @@ -928,14 +960,14 @@ protected function buildChadoRecords($values, bool $is_store) { // If the core table is set in the base record ids array and the // value is not 0 then we can set this condition now! - if (array_key_exists($core_table, $context['base_record_ids']) and $context['base_record_ids'][$core_table] != 0) { - $records[$table_name][$delta]['conditions'][$chado_column] = $context['base_record_ids'][$core_table]; + if (array_key_exists($core_table, $this->base_record_ids) and $this->base_record_ids[$core_table] != 0) { + $records[$table_name][$delta]['conditions'][$chado_column] = $this->base_record_ids[$core_table]; } // If the base record ID is 0 then this is an insert and we // don't yet have the base record ID. So, leave in the message // to replace the ID so we can do so later. - if (array_key_exists($base_table, $context['base_record_ids']) and $context['base_record_ids'][$base_table] != 0) { - $records[$table_name][$delta]['conditions'][$chado_column]['value'] = $context['base_record_ids'][$base_table]; + if (array_key_exists($base_table, $this->base_record_ids) and $this->base_record_ids[$base_table] != 0) { + $records[$table_name][$delta]['conditions'][$chado_column]['value'] = $this->base_record_ids[$base_table]; } } @@ -943,10 +975,9 @@ protected function buildChadoRecords($values, bool $is_store) { } } - $this->field_debugger->summarizeBuiltRecords($context['base_record_ids'], $records); + $this->field_debugger->summarizeBuiltRecords($this->base_record_ids, $records); return [ - 'base_tables' => $context['base_record_ids'], 'records' => $records ]; } @@ -995,8 +1026,8 @@ protected function buildChadoRecords_store_id(array &$records, int $delta, array $table_alias = $chado_table; if (array_key_exists('chado_table_alias', $storage_settings)) { $table_alias = $storage_settings['chado_table_alias']; - $context['table_alias'][$table_alias] = $chado_table; } + $this->setChadoTableAliasMapping($chado_table, $table_alias, $context['field_name'], $context['property_key']); // Get the value if it is set. $record_id = $prop_value->getValue(); @@ -1014,8 +1045,8 @@ protected function buildChadoRecords_store_id(array &$records, int $delta, array ]; // Now we add the chado table to our array of core tables // so that we can replace it with the value for the record later. - if (!array_key_exists($chado_table, $context['base_record_ids'])) { - $context['base_record_ids'][$chado_table] = $record_id; + if (!array_key_exists($chado_table, $this->base_record_ids)) { + $this->base_record_ids[$chado_table] = $record_id; } } // However, if the record_id was set when the values were passed in, @@ -1027,7 +1058,7 @@ protected function buildChadoRecords_store_id(array &$records, int $delta, array 'operation' => $context['operation'] ]; - $context['base_record_ids'][$table_alias] = $record_id; + $this->base_record_ids[$table_alias] = $record_id; } } @@ -1075,8 +1106,8 @@ protected function buildChadoRecords_store_pkey(array &$records, int $delta, arr $table_alias = $chado_table; if (array_key_exists('chado_table_alias', $storage_settings)) { $table_alias = $storage_settings['chado_table_alias']; - $context['table_alias'][$table_alias] = $chado_table; } + $this->setChadoTableAliasMapping($chado_table, $table_alias, $context['field_name'], $context['property_key']); $link_record_id = $prop_value->getValue(); @@ -1134,7 +1165,7 @@ protected function buildChadoRecords_store_link(array &$records, int $delta, arr $linker_alias = (array_key_exists('right_table_alias', $storage_settings)) ? $storage_settings['right_table_alias'] : $linker; // Then check if the right table has a store_id and if so, use it instead. // (e.g. analysisfeature.analysis_id = analysis.analysis_id) - if (array_key_exists($storage_settings['right_table'], $context['base_record_ids'])) { + if (array_key_exists($storage_settings['right_table'], $this->base_record_ids)) { $link_base = $storage_settings['right_table']; $link_base_id = $storage_settings['right_table_id']; $linker = $storage_settings['left_table']; @@ -1143,9 +1174,7 @@ protected function buildChadoRecords_store_link(array &$records, int $delta, arr } // If an alias was set then make sure it's added to the context. - if ($linker_alias != $linker) { - $context['table_alias'][$linker_alias] = $linker; - } + $this->setChadoTableAliasMapping($linker, $linker_alias, $context['field_name'], $context['property_key']); // @debug print "We decided it should be BASE $link_base.$link_base_id => LINKER $linker.$linker_id.\n"; // We want to ensure that the linker table has a field added with @@ -1170,7 +1199,7 @@ protected function buildChadoRecords_store_link(array &$records, int $delta, arr 'We had to use backwards compatible mode for :name.:key property type with an action of store_link.' .' Please update the code for this field to use left/right table notation for the store_link property.' .' Backwards compatible mode should allow this field to save/load data but may result in errors with token replacement and publishing.', - [':name' => $context['field_name'], ':key' => $context['key']] + [':name' => $context['field_name'], ':key' => $context['property_key']] ); } } @@ -1213,8 +1242,8 @@ protected function buildChadoRecords_store(array &$records, int $delta, array $s $table_alias = $chado_table; if (array_key_exists('chado_table_alias', $storage_settings)) { $table_alias = $storage_settings['chado_table_alias']; - $context['table_alias'][$table_alias] = $chado_table; } + $this->setChadoTableAliasMapping($chado_table, $table_alias, $context['field_name'], $context['property_key']); // Now grab the column we are interested in. $chado_column = $storage_settings['chado_column']; @@ -1280,8 +1309,8 @@ protected function buildChadoRecords_read_value(array &$records, int $delta, arr $table_alias = $chado_table; if (array_key_exists('chado_table_alias', $storage_settings)) { $table_alias = $storage_settings['chado_table_alias']; - $context['table_alias'][$table_alias] = $chado_table; } + $this->setChadoTableAliasMapping($chado_table, $table_alias, $context['field_name'], $context['property_key']); $chado_column = $storage_settings['chado_column']; @@ -1745,14 +1774,14 @@ public function validateValues($values) { $this->field_debugger->summarizeChadoStorage($this, 'At the beginning of ChadoStorage::validateValues'); $build = $this->buildChadoRecords($values, TRUE); - $base_tables = $build['base_tables']; + $base_tables = $this->base_record_ids; $records = $build['records']; $violations = []; // We only need to validate the base table properties because // the linker table values get completely replaced on an update and // should not exist for an insert. - foreach ($build['base_tables'] as $base_table => $record_id) { + foreach ($this->base_record_ids as $base_table => $record_id) { foreach ($records[$base_table] as $delta => $record) { $record = $records[$base_table][$delta]; $this->validateRequired($values, $base_table, $record_id, $record, $violations); @@ -1768,4 +1797,92 @@ public function validateValues($values) { return $violations; } + + /** + * Retrieve the chado table name when given the table alias. + * + * @param string $table_alias + * The table alias for which you would like to look up the mapping. + * @param array $property_storage + * The storage information for the property when available. This is used + * to set the table alias mapping if it is not already set. + * + * @return string $chado_table + * The name of the chado table the alias referrences. + */ + protected function getChadoTableFromAlias(string $table_alias, array $property_storage = []) { + + // If the mapping has not yet been set then we need to do some + // detective work to figure it out... Let's do that first + // and then update the mapping. + if (!array_key_exists($table_alias, $this->table_alias_mapping)) { + // If there is a chado table set in the property storage details + // then we can use it to set the mapping and return it. + if (array_key_exists('chado_table', $property_storage)) { + $chado_table = $property_storage['chado_table']; + $this->table_alias_mapping[$table_alias] = $chado_table; + } + // If the action is store_link then this might be the right or left table + // alias so check those as well. + elseif (array_key_exists('right_table_alias', $property_storage)) { + $right_table_alias = $property_storage['right_table_alias']; + if ($right_table_alias == $table_alias) { + $chado_table = $proeprty_storage['right_table']; + } + $this->table_alias_mapping[$table_alias] = $chado_table; + } + elseif (array_key_exists('left_table_alias', $property_storage)) { + $left_table_alias = $property_storage['left_table_alias']; + if ($left_table_alias == $table_alias) { + $chado_table = $proeprty_storage['left_table']; + } + $this->table_alias_mapping[$table_alias] = $chado_table; + } + // Otherwise, the default table alias is the same as the table name + // so update the mapping and return the table name. + else { + $chado_table = $table_alias; + $this->table_alias_mapping[$table_alias] = $chado_table; + } + } + + return $this->table_alias_mapping[$table_alias]; + } + + /** + * Retrieves the table alias for a given chado table when the field and property key are known. + * + * NOTE: buildChadoRecords() must have been called first! + * + * @param string $field_name + * @param string $property_key + * @param string $chado_table + */ + protected function getTableAliasForChadoTable($field_name, $property_key, $chado_table) { + + if (array_key_exists($field_name, $this->reverse_alias_mapping)) { + if (array_key_exists($property_key, $this->reverse_alias_mapping[$field_name])) { + if (array_key_exists($chado_table, $this->reverse_alias_mapping[$field_name][$property_key])) { + return $this->reverse_alias_mapping[$field_name][$property_key][$chado_table]; + } + } + } + + return NULL; + } + + /** + * Sets the mapping between chado tables and their alias' + * + * @param $chado_table + * @param $table_alias + * @param string $field_name + * @param string $property_key + */ + protected function setChadoTableAliasMapping($chado_table, $table_alias, $field_name, $property_key) { + + $this->table_alias_mapping[$table_alias] = $chado_table; + $this->reverse_alias_mapping[$field_name][$property_key][$chado_table] = $table_alias; + + } } From f64919cf4c24fc35a886d673134f92795f462d8e Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 18 Oct 2023 16:58:26 -0600 Subject: [PATCH 31/74] Update insert and setRecordIds(). --- .../src/Plugin/TripalStorage/ChadoStorage.php | 70 +++++++++++-------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index c0da1fe91..bd8c82ae4 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -206,19 +206,20 @@ public function insertValues(&$values) : bool { try { // First: Insert the base table records. - foreach ($this->base_record_ids as $base_table => $record_id) { - foreach ($records[$base_table] as $delta => $record) { - $record_id = $this->insertChadoRecord($records, $base_table, $delta, $record); - $this->base_record_ids[$base_table] = $record_id; + // Note: Assumes there is only a single base table. + foreach ($this->base_record_ids as $base_table_alias => $record_id) { + foreach ($records[$base_table_alias] as $delta => $record) { + $record_id = $this->insertChadoRecord($records, $base_table_alias, $delta, $record); + $this->base_record_ids[$base_table_alias] = $record_id; } } // Second: Insert non base table records. - foreach ($records as $chado_table => $deltas) { + foreach ($records as $chado_table_alias => $deltas) { foreach ($deltas as $delta => $record) { // Skip base table records. - if (in_array($chado_table, array_keys($this->base_record_ids))) { + if (in_array($chado_table_alias, array_keys($this->base_record_ids))) { continue; } @@ -239,12 +240,12 @@ public function insertValues(&$values) : bool { // Replace linking fields with values foreach ($record['fields'] as $column => $val) { if (is_array($val) and $val[0] == 'REPLACE_BASE_RECORD_ID') { - $base_table = $val[1]; - $records[$chado_table][$delta]['fields'][$column] = $this->base_record_ids[$base_table]; - $record['fields'][$column] = $this->base_record_ids[$base_table]; + $base_table_alias = $val[1]; + $records[$chado_table_alias][$delta]['fields'][$column] = $this->base_record_ids[$base_table_alias]; + $record['fields'][$column] = $this->base_record_ids[$base_table_alias]; } } - $this->insertChadoRecord($records, $chado_table, $delta, $record); + $this->insertChadoRecord($records, $chado_table_alias, $delta, $record); } } $this->setRecordIds($values, $records); @@ -617,38 +618,45 @@ protected function setRecordIds(&$values, $records) { } $action = $prop_storage_settings['action']; - // Get the base table information. - $base_table = $storage_plugin_settings['base_table']; - $base_table_def = $schema->getTableDef($base_table, ['format' => 'drupal']); - $base_table_pkey = $base_table_def['primary key']; - - // Get the Chado table information. If one is not specified (as - // in the case of single value fields) then default to the base - // table. - $chado_table = $base_table; - $chado_table_def = $base_table_def; - $chado_table_pkey = $base_table_pkey; + // Get the base table information and use it as the default for if + // a chado_table is not specified (as in the case of single value fields). + $chado_table = $storage_plugin_settings['base_table']; + // Now check for if the chado_table is specified as it should be for + // store_id + store_pkey properties. if (array_key_exists('chado_table', $prop_storage_settings)) { $chado_table = $prop_storage_settings['chado_table']; - $chado_table_def = $schema->getTableDef($chado_table, ['format' => 'drupal']); - $chado_table_pkey = $chado_table_def['primary key']; } + // If it is a store_link property then we have to deal with left/right + // tables so let's do that now. + // Note: If the action is store_link and the right_table was not set then we + // want to be backwards compatible with the old store_link approach. + elseif (array_key_exists('right_table', $prop_storage_settings)) { + $chado_table = $prop_storage_settings['right_table']; + if (array_key_exists($prop_storage_settings['right_table'], $this->base_record_ids)) { + $chado_table = $prop_storage_settings['left_table']; + } + } + + // Grab the pkey using the schema definition. + $chado_table_def = $schema->getTableDef($chado_table, ['format' => 'drupal']); + $chado_table_pkey = $chado_table_def['primary key']; + + // Now grab the table alias. + $chado_table_alias = $this->getTableAliasForChadoTable($field_name, $key, $chado_table); // If this is the record_id property then set its value. if ($action == 'store_id') { - $record_id = $records[$chado_table][0]['conditions'][$chado_table_pkey]['value']; + $record_id = $records[$chado_table_alias][0]['conditions'][$chado_table_pkey]['value']; $values[$field_name][$delta][$key]['value']->setValue($record_id); } // If this is the linked record_id property then set its value. if ($action == 'store_pkey') { - $record_id = $records[$chado_table][$delta]['conditions'][$chado_table_pkey]['value']; + $record_id = $records[$chado_table_alias][$delta]['conditions'][$chado_table_pkey]['value']; $values[$field_name][$delta][$key]['value']->setValue($record_id); } // If this is a property managing a linked record ID then set it too. if ($action == 'store_link') { - // @todo we should use left/right here rather than assuming there is - // only a single base table. - $record_id = $records[$base_table][0]['conditions'][$base_table_pkey]['value']; + $record_id = $records[$chado_table_alias][0]['conditions'][$chado_table_pkey]['value']; $values[$field_name][$delta][$key]['value']->setValue($record_id); } } @@ -1195,6 +1203,10 @@ protected function buildChadoRecords_store_link(array &$records, int $delta, arr $bc_chado_table = $storage_settings['chado_table']; $bc_chado_column = $storage_settings['chado_column']; $records[$bc_chado_table][$delta]['fields'][$bc_chado_column] = ['REPLACE_BASE_RECORD_ID', $context['base_table']]; + + // We also need to set the mapping so that the id can be replaced later. + $this->setChadoTableAliasMapping($bc_chado_table, $bc_chado_table, $context['field_name'], $context['property_key']); + $this->logger->warning( 'We had to use backwards compatible mode for :name.:key property type with an action of store_link.' .' Please update the code for this field to use left/right table notation for the store_link property.' @@ -1868,6 +1880,8 @@ protected function getTableAliasForChadoTable($field_name, $property_key, $chado } } + print "\nWe could not reverse lookup for $field_name > $property_key : $chado_table. Reverse Mapping: " . print_r($this->reverse_alias_mapping, TRUE) . "Forward Mapping: " . print_r($this->table_alias_mapping, TRUE); + return NULL; } From 039596844b1d3c0a6c9281a32ca526a48ba637e4 Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 18 Oct 2023 17:02:54 -0600 Subject: [PATCH 32/74] Works for insert but not update or load yet. Progress tho!!! --- .../Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php index 4fd1eb769..597b56b8e 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php @@ -383,6 +383,7 @@ public function testCRUDForSinglePropField($prop_field_name) { $$varname = $records[0]; } + /* // Test Case: Load values existing in Chado. // --------------------------------------------------------- // First we want to reset all the chado storage arrays to ensure we are @@ -507,5 +508,7 @@ public function testCRUDForSinglePropField($prop_field_name) { // NOT YET IMPLEMENTED IN CHADOSTORAGE. + */ + } } From 79ce81051f7ded2e8ea870f32b54941d97db3c46 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Thu, 19 Oct 2023 10:07:47 -0600 Subject: [PATCH 33/74] Alias' are working for load now --- .../src/Plugin/TripalStorage/ChadoStorage.php | 33 +++++++++---------- .../ChadoLinkerPropertyDefaultTest.php | 4 +-- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index bd8c82ae4..96b8f35a9 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -418,13 +418,13 @@ public function updateValues(&$values) : bool { * Selects a single record from Chado. * * @param array $records - * @param string $chado_table + * @param string $chado_table_alias * @param integer $delta * @param array $record * * @throws \Exception */ - public function selectChadoRecord(&$records, $base_tables, $chado_table, $delta, $record) { + public function selectChadoRecord(&$records, $base_tables, $chado_table_alias, $delta, $record) { if (!array_key_exists('conditions', $record)) { throw new \Exception($this->t('Cannot select record in the Chado "@table" table due to missing conditions. Record: @record', @@ -438,6 +438,8 @@ public function selectChadoRecord(&$records, $base_tables, $chado_table, $delta, ['@table' => $chado_table, '@record' => print_r($record, TRUE)])); } + $chado_table = $this->getChadoTableFromAlias($chado_table_alias); + // Select the fields in the chado table. $select = $this->connection->select('1:'.$chado_table, 'ct'); $select->fields('ct', array_keys($record['fields'])); @@ -479,7 +481,7 @@ public function selectChadoRecord(&$records, $base_tables, $chado_table, $delta, throw new \Exception($this->t('Failed to select record in the Chado "@table" table. Record: @record', ['@table' => $chado_table, '@record' => print_r($record, TRUE)])); } - $records[$chado_table][$delta]['fields'] = $results->fetchAssoc(); + $records[$chado_table_alias][$delta]['fields'] = $results->fetchAssoc(); } /** @@ -496,9 +498,9 @@ public function loadValues(&$values) : bool { $transaction_chado = $this->connection->startTransaction(); try { - foreach ($records as $chado_table => $deltas) { + foreach ($records as $chado_table_alias => $deltas) { foreach ($deltas as $delta => $record) { - $this->selectChadoRecord($records, $base_tables, $chado_table, $delta, $record); + $this->selectChadoRecord($records, $base_tables, $chado_table_alias, $delta, $record); } } $this->setPropValues($values, $records); @@ -704,26 +706,20 @@ protected function setPropValues(&$values, $records) { if ($action == 'store_pkey') { continue; } - - // If this is a linked record then the ID should already be in the - // the conditions of the base table. if ($action == 'store_link') { - $base_table = $storage_plugin_settings['base_table']; - $base_table_def = $schema->getTableDef($base_table, ['format' => 'drupal']); - $base_table_pkey = $base_table_def['primary key']; - $link_id = $records[$base_table][0]['conditions'][$base_table_pkey]['value']; - $values[$field_name][$delta][$key]['value']->setValue($link_id); + continue; } // Get the values of properties that can be stored. if ($action == 'store') { $chado_table = $prop_storage_settings['chado_table']; + $chado_table_alias = $this->getTableAliasForChadoTable($field_name, $key, $chado_table); $chado_column = $prop_storage_settings['chado_column']; - if (array_key_exists($chado_table, $records)) { - if (array_key_exists($delta, $records[$chado_table])) { - if (array_key_exists($chado_column, $records[$chado_table][$delta]['fields'])) { - $value = $records[$chado_table][$delta]['fields'][$chado_column]; + if (array_key_exists($chado_table_alias, $records)) { + if (array_key_exists($delta, $records[$chado_table_alias])) { + if (array_key_exists($chado_column, $records[$chado_table_alias][$delta]['fields'])) { + $value = $records[$chado_table_alias][$delta]['fields'][$chado_column]; $values[$field_name][$delta][$key]['value']->setValue($value); } } @@ -749,9 +745,10 @@ protected function setPropValues(&$values, $records) { // The base table is the left table of the first part of the path. $chado_table = $left_table; } + $chado_table_alias = $this->getTableAliasForChadoTable($field_name, $key, $chado_table); $chado_column = $prop_storage_settings['chado_column']; $as = array_key_exists('as', $prop_storage_settings) ? $prop_storage_settings['as'] : $chado_column; - $value = $records[$chado_table][$delta]['fields'][$as]; + $value = $records[$chado_table_alias][$delta]['fields'][$as]; $values[$field_name][$delta][$key]['value']->setValue($value); } diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php index 597b56b8e..c77999b3f 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php @@ -383,7 +383,7 @@ public function testCRUDForSinglePropField($prop_field_name) { $$varname = $records[0]; } - /* + // Test Case: Load values existing in Chado. // --------------------------------------------------------- // First we want to reset all the chado storage arrays to ensure we are @@ -450,7 +450,7 @@ public function testCRUDForSinglePropField($prop_field_name) { ); } - +/* // Test Case: Update values in Chado using ChadoStorage. // --------------------------------------------------------- // When updating we need all the store id/pkey/link records From 839ec01b5c2c91c7c9cc6dc01192a069202a3746 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Thu, 19 Oct 2023 13:36:52 -0600 Subject: [PATCH 34/74] Working for updates. --- .../src/Plugin/TripalStorage/ChadoStorage.php | 26 +++++++++++-------- .../ChadoLinkerPropertyDefaultTest.php | 3 --- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index 96b8f35a9..54120bb70 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -349,21 +349,22 @@ public function updateValues(&$values) : bool { $build = $this->buildChadoRecords($values, TRUE); $records = $build['records']; + $base_tables = $this->base_record_ids; $transaction_chado = $this->connection->startTransaction(); try { // Handle base table records first. - foreach ($records as $chado_table => $deltas) { + foreach ($records as $chado_table_alias => $deltas) { foreach ($deltas as $delta => $record) { // If this is the base table then do an update. - if (in_array($chado_table, array_keys($base_tables))) { + if (in_array($chado_table_alias, array_keys($base_tables))) { if (!array_key_exists('conditions', $record)) { throw new \Exception($this->t('Cannot update record in the Chado "@table" table due to missing conditions. Record: @record', ['@table' => $chado_table, '@record' => print_r($record, TRUE)])); } - $this->updateChadoRecord($records, $chado_table, $delta, $record); + $this->updateChadoRecord($records, $chado_table_alias, $delta, $record); continue; } } @@ -373,11 +374,11 @@ public function updateValues(&$values) : bool { // with updates. This is necessary because we may violate unique // constraints if we don't e.g. changing the order of records with a // rank. - foreach ($records as $chado_table => $deltas) { + foreach ($records as $chado_table_alias => $deltas) { foreach ($deltas as $delta => $record) { // Skip base table records. - if (in_array($chado_table, array_keys($base_tables))) { + if (in_array($chado_table_alias, array_keys($base_tables))) { continue; } @@ -386,23 +387,24 @@ public function updateValues(&$values) : bool { if (!$this->hasValidConditions($record)) { continue; } - $this->deleteChadoRecord($records, $chado_table, $delta, $record); + $this->deleteChadoRecord($records, $chado_table_alias, $delta, $record); } } // Now insert all new values for the non-base table records. - foreach ($records as $chado_table => $deltas) { + foreach ($records as $chado_table_alias => $deltas) { foreach ($deltas as $delta => $record) { // Skip base table records. - if (in_array($chado_table, array_keys($base_tables))) { + if (in_array($chado_table_alias, array_keys($base_tables))) { continue; } // Skip records that were supposed to be deleted (and were). if ($this->isEmptyRecord($record)) { continue; } - $this->insertChadoRecord($records, $chado_table, $delta, $record); + + $this->insertChadoRecord($records, $chado_table_alias, $delta, $record); } } $this->setRecordIds($values, $records); @@ -524,7 +526,9 @@ public function loadValues(&$values) : bool { * @param array $record * @throws \Exception */ - private function deleteChadoRecord(&$records, $chado_table, $delta, $record) { + private function deleteChadoRecord(&$records, $chado_table_alias, $delta, $record) { + + $chado_table = $this->getChadoTableFromAlias($chado_table_alias); $schema = $this->connection->schema(); $table_def = $schema->getTableDef($chado_table, ['format' => 'drupal']); @@ -554,7 +558,7 @@ private function deleteChadoRecord(&$records, $chado_table, $delta, $record) { } // Unset the record Id for this deleted record. - $records[$chado_table][$delta]['conditions'][$pkey]['value'] = 0; + $records[$chado_table_alias][$delta]['conditions'][$pkey]['value'] = 0; } /** diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php index c77999b3f..007197133 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php @@ -450,7 +450,6 @@ public function testCRUDForSinglePropField($prop_field_name) { ); } -/* // Test Case: Update values in Chado using ChadoStorage. // --------------------------------------------------------- // When updating we need all the store id/pkey/link records @@ -508,7 +507,5 @@ public function testCRUDForSinglePropField($prop_field_name) { // NOT YET IMPLEMENTED IN CHADOSTORAGE. - */ - } } From 68ef16bc9a0bf53fbdff3f002042dd140fb8ddae Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Thu, 19 Oct 2023 16:13:06 -0600 Subject: [PATCH 35/74] Remove original functional test as it's been replaced by multiple kernel tests. --- .../Functional/Plugin/ChadoStorageTest.php | 576 ------------------ 1 file changed, 576 deletions(-) delete mode 100644 tripal_chado/tests/src/Functional/Plugin/ChadoStorageTest.php diff --git a/tripal_chado/tests/src/Functional/Plugin/ChadoStorageTest.php b/tripal_chado/tests/src/Functional/Plugin/ChadoStorageTest.php deleted file mode 100644 index 1c8056afd..000000000 --- a/tripal_chado/tests/src/Functional/Plugin/ChadoStorageTest.php +++ /dev/null @@ -1,576 +0,0 @@ -set('is_a_test_environment', TRUE); - - // Create a new test schema for us to use. - $connection = $this->createTestSchema(ChadoTestBrowserBase::PREPARE_TEST_CHADO); - - // All Chado storage testing requires an entity. - $content_entity = $this->createTripalContent(); - $content_entity_id = $content_entity->id(); - $content_type = $content_entity->getType(); - $content_type_obj = \Drupal\tripal\Entity\TripalEntityType::load($content_type); - - $this->content_entity_id = $content_entity_id; - $this->content_type = $content_type; - - // Specifically we are mocking our example based on a "Gene" entity type (bundle). - // Stored in the feature Chado table: - // name: test_gene_name, uniquename: test_gene_uname, type: gene (SO:0000704) - // organism) genus: Oryza, species: sativa, common_name: rice, - // abbreviation: O.sativa, infraspecific_name: Japonica, - // type: species_group (TAXRANK:0000010), comment: 'This is rice' - // Feature Properties) - // - type: note (rdfs:comment), value: "Note 1", rank: 0 - // - type: note (rdfs:comment), value: "Note 2", rank: 2 - // - type: note (rdfs:comment), value: "Note 3", rank: 1 - // The Gene entity type has 3 fields: Gene Name, Notes, Organism. - - // Add the organism record. - $infra_type_id = $this->getCvtermID('TAXRANK', '0000010'); - $query = $connection->insert('1:organism'); - $query->fields([ - 'genus' => 'Oryza', - 'species' => 'sativa', - 'common_name' => 'rice', - 'abbreviation' => 'O.sativa', - 'infraspecific_name' => 'Japonica', - 'type_id' => $infra_type_id, - 'comment' => 'This is rice' - ]); - $this->organism_id = $query->execute(); - - // Add the gene record. - $gene_type_id = $this->getCvtermID('SO', '0000704'); - $query = $connection->insert('1:feature'); - $query->fields([ - 'name' => 'test_gene_name', - 'uniquename' => 'test_gene_uname', - 'type_id' => $gene_type_id, - 'organism_id' => $this->organism_id, - ]); - $this->feature_id = $query->execute(); - - // Add featureprop notes: - $note_type_id = $this->getCvtermID('rdfs', 'comment'); - $this->featureprop_id[0] = $connection->insert('1:featureprop') - ->fields([ - 'feature_id' => $this->feature_id, - 'type_id' => $note_type_id, - 'value' => "Note 1", - 'rank' => 0, - ]) - ->execute(); - $this->featureprop_id[2] = $connection->insert('1:featureprop') - ->fields([ - 'feature_id' => $this->feature_id, - 'type_id' => $note_type_id, - 'value' => "Note 2", - 'rank' => 2, - ]) - ->execute(); - $this->featureprop_id[1] = $connection->insert('1:featureprop') - ->fields([ - 'feature_id' => $this->feature_id, - 'type_id' => $note_type_id, - 'value' => "Note 3", - 'rank' => 1, - ]) - ->execute(); - - // We need to make sure the CVs we're going to use are registered. - // they should already be loaded in the test Chado instance. - $vmanager = \Drupal::service('tripal.collection_plugin_manager.vocabulary'); - $idsmanager = \Drupal::service('tripal.collection_plugin_manager.idspace'); - - $vocabulary = $vmanager->createCollection('SIO', 'chado_vocabulary'); - $idSpace = $idsmanager->createCollection('SIO', 'chado_id_space'); - $idSpace->setDefaultVocabulary($vocabulary->getName()); - - $vocabulary = $vmanager->createCollection('schema', 'chado_vocabulary'); - $idSpace = $idsmanager->createCollection('schema', 'chado_id_space'); - $idSpace->setDefaultVocabulary($vocabulary->getName()); - - $vocabulary = $vmanager->createCollection('sequence', 'chado_vocabulary'); - $idSpace = $idsmanager->createCollection('SO', 'chado_id_space'); - $idSpace->setDefaultVocabulary($vocabulary->getName()); - - $vocabulary = $vmanager->createCollection('ncit', 'chado_vocabulary'); - $idSpace = $idsmanager->createCollection('NCIT', 'chado_id_space'); - $idSpace->setDefaultVocabulary($vocabulary->getName()); - - $vocabulary = $vmanager->createCollection('OBCS', 'chado_vocabulary'); - $idSpace = $idsmanager->createCollection('OBCS', 'chado_id_space'); - $idSpace->setDefaultVocabulary($vocabulary->getName()); - - $vocabulary = $vmanager->createCollection('obi', 'chado_vocabulary'); - $idSpace = $idsmanager->createCollection('OBI', 'chado_id_space'); - $idSpace->setDefaultVocabulary($vocabulary->getName()); - - $vocabulary = $vmanager->createCollection('rdfs', 'chado_vocabulary'); - $idSpace = $idsmanager->createCollection('rdfs', 'chado_id_space'); - $idSpace->setDefaultVocabulary($vocabulary->getName()); - - $vocabulary = $vmanager->createCollection('taxonomic_rank', 'chado_vocabulary'); - $idSpace = $idsmanager->createCollection('TAXRANK', 'chado_id_space'); - $idSpace->setDefaultVocabulary($vocabulary->getName()); - - $vocabulary = $vmanager->createCollection('local', 'chado_vocabulary'); - $idSpace = $idsmanager->createCollection('local', 'chado_id_space'); - $idSpace->setDefaultVocabulary($vocabulary->getName()); - - // This term is missing from the current prepared test Chado so we - // manually add it. - $this->createTripalTerm([ - 'vocab_name' => 'SIO', - 'id_space_name' => 'SIO', - 'term' => [ - 'name' => 'record identifier', - 'accession' =>'000729', - ]], - 'chado_id_space', 'chado_vocabulary' - ); - } - - /** - * Tests the ChadoIdSpace Class - * - * @Depends Drupal\tripal_chado\Task\ChadoInstallerTest::testPerformTaskInstaller - * - */ - public function testChadoStorage() { - - // Get plugin managers we need for our testing. - $storage_manager = \Drupal::service('tripal.storage'); - $chado_storage = $storage_manager->createInstance('chado_storage'); - - // $testEnviro_chado = $this->getTestSchema(); - // $testEnviro_chado_schemaname = $testEnviro_chado->getSchemaName(); - // $coreEnviro_chado = \Drupal::service('tripal_chado.database'); - // $coreEnviro_chado_schemaname = $coreEnviro_chado->getSchemaName(); - // print "\ntestChadoStorage: $testEnviro_chado_schemaname = $coreEnviro_chado_schemaname.\n"; - // $this->assertEquals($testEnviro_chado_schemaname, $coreEnviro_chado_schemaname, "Core Services are not using the test schema."); - - // For the ChadoStorage->addTypes() and ChadoStorage->loadValues() - // We are going to progressively test these methods with more + more fields. - // Hence, I'm starting the values variable here to be added to as we go. - // The types will be stored in the $chado_storage service object. - $values = []; - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // -- Single value + single property field - // Stored in feature.name; Term: schema:name. - // Value: test_gene_name - $field_name = 'schema__name'; - $field_label = 'Gene Name'; - $chado_table = 'feature'; - $chado_column = 'name'; - $storage_settings = [ - 'storage_plugin_id' => 'chado_storage', - 'storage_plugin_settings' => [ - 'base_table' => $chado_table, - ], - ]; - - - // Testing the Property Type + Value class creation - // + prepping for future tests. - //$this->addFieldPropertyCVterms(); - $propertyTypes = [ - 'feature_id' => new ChadoIntStoragePropertyType($this->content_type, $field_name, 'feature_id', 'SIO:000729', [ - 'action' => 'store_id', - 'drupal_store' => TRUE, - 'chado_table' => $chado_table, - 'chado_column' => $chado_column, - ]), - 'name' => new ChadoVarCharStoragePropertyType($this->content_type, $field_name, 'name', 'schema:name', 255, [ - 'action' => 'store', - 'chado_table' => $chado_table, - 'chado_column' => $chado_column, - ]), - ]; - $propertyValues = [ - 'feature_id' => new StoragePropertyValue( - $this->content_type, - $field_name, - 'feature_id', - 'SIO:000729', - $this->content_entity_id, - $this->feature_id - ), - 'name' => new StoragePropertyValue( - $this->content_type, - $field_name, - 'name', - 'schema:name', - $this->content_entity_id, - ), - ]; - $this->assertIsObject($propertyTypes['feature_id'], "Unable to create feature_id ChadoIntStoragePropertyType: $field_name, record_id"); - $this->assertIsObject($propertyValues['feature_id'], "Unable to create feature_id StoragePropertyValue: $field_name, record_id, $this->content_entity_id"); - $this->assertIsObject($propertyTypes['name'], "Unable to create feature.name ChadoIntStoragePropertyType: $field_name, value"); - $this->assertIsObject($propertyValues['name'], "Unable to create feature.name StoragePropertyValue: $field_name, value, $this->content_entity_id"); - - // Make sure the values start empty. - $this->assertEquals($this->feature_id, $propertyValues['feature_id']->getValue(), "The $field_name feature_id property should already be set."); - $this->assertTrue(empty($propertyValues['name']->getValue()), "The $field_name feature.name property should not have a value."); - - // Now test ChadoStorage->addTypes() - // param array $types = Array of \Drupal\tripal\TripalStorage\StoragePropertyTypeBase objects. - $chado_storage->addTypes($field_name, $propertyTypes); - $retrieved_types = $chado_storage->getTypes(); - $this->assertIsArray($retrieved_types, "Unable to retrieve the PropertyTypes after adding $field_name."); - // @update to match new format $this->assertCount(2, $retrieved_types, "Did not revieve the expected number of PropertyTypes after adding $field_name."); - - // We also need FieldConfig classes for loading values. - // We're going to create a TripalField and see if that works. - $fieldconfig = new FieldConfigMock(['field_name' => $field_name, 'entity_type' => $this->content_type]); - $fieldconfig->setMock(['label' => $field_label, 'settings' => $storage_settings]); - $chado_storage->addFieldDefinition($field_name, $fieldconfig); - - // Next we actually load the values. - $values[$field_name] = [ - 0 => [ - 'name'=> [ - 'value' => $propertyValues['name'], - ], - 'feature_id' => [ - 'value' => $propertyValues['feature_id'], - ], - ], - ]; - $success = $chado_storage->loadValues($values); - $this->assertTrue($success, "Loading values after adding $field_name was not success (i.e. did not return TRUE)."); - - // Then we test that the values are now in the types that we passed in. - $this->assertEquals('test_gene_name', $values['schema__name'][0]['name']['value']->getValue(), 'The gene name value was not loaded properly.'); - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // -- Multi-value single property field - // Stored in featureprop.value; Term: rdfs:comment. - // Values: - // - type: note (rdfs:comment), value: "Note 1", rank: 0 - // - type: note (rdfs:comment), value: "Note 2", rank: 2 - // - type: note (rdfs:comment), value: "Note 3", rank: 1 - $field_name = 'rdfs__comment'; - $field_term_string = 'rdfs:comment'; - $chado_table = 'featureprop'; - $chado_column = 'value'; - $chado_table = 'featureprop'; - $base_table = 'feature'; - $storage_settings = [ - 'storage_plugin_id' => 'chado_storage', - 'storage_plugin_settings' => [ - 'base_table' => $base_table, - ], - ]; - - $propertyTypes = [ - 'feature_id' => new ChadoIntStoragePropertyType($this->content_type, $field_name, 'feature_id', 'SIO:000729', [ - 'action' => 'store_id', - 'drupal_store' => TRUE, - 'chado_table' => 'feature', - 'chado_column' => 'feature_id', - ]), - 'featureprop_id' => new ChadoIntStoragePropertyType($this->content_type, $field_name, 'featureprop_id', 'SIO:000729', [ - 'action' => 'store_pkey', - 'chado_table' => 'featureprop', - 'chado_column' => 'featureprop_id', - ]), - 'fk_feature_id' => new ChadoIntStoragePropertyType($this->content_type, $field_name, 'fk_feature_id', 'SO:0000110', [ - 'action' => 'store_link', - 'left_table' => 'feature', - 'left_table_id' => 'feature_id', - 'right_table' => 'featureprop', - 'right_table_id' => 'feature_id', - ]), - 'type_id' => new ChadoIntStoragePropertyType($this->content_type, $field_name, 'type_id', 'schema:additionalType', [ - 'action' => 'store', - 'chado_table' => 'featureprop', - 'chado_column' => 'type_id', - ]), - 'value' => new ChadoIntStoragePropertyType($this->content_type, $field_name, 'value', 'NCIT:C25712', [ - 'action' => 'store', - 'chado_table' => 'featureprop', - 'chado_column' => 'value', - ]), - 'rank' => new ChadoIntStoragePropertyType($this->content_type, $field_name, 'rank', 'OBCS:0000117', [ - 'action' => 'store', - 'chado_table' => 'featureprop', - 'chado_column' => 'rank', - ]), - ]; - foreach ($propertyTypes as $key => $propType) { - $this->assertIsObject($propType, "Unable to create the *StoragePropertyType: $field_name, $key"); - } - - // Testing the Property Value class creation. - $propertyValues = [ - 'feature_id' => new StoragePropertyValue($this->content_type, $field_name, 'feature_id', 'SIO:000729', $this->content_entity_id, $this->feature_id), - 'featureprop_id' => new StoragePropertyValue($this->content_type, $field_name, 'featureprop_id', 'SIO:000729', $this->content_entity_id), - 'fk_feature_id' => new StoragePropertyValue($this->content_type, $field_name, 'fk_feature_id', 'SO:0000110', $this->content_entity_id), - 'type_id' => new StoragePropertyValue($this->content_type, $field_name, 'type_id', 'schema:additionalType', $this->content_entity_id), - 'value' => new StoragePropertyValue($this->content_type, $field_name, 'value', 'NCIT:C25712', $this->content_entity_id), - 'rank' => new StoragePropertyValue($this->content_type, $field_name, 'rank', 'OBCS:0000117', $this->content_entity_id), - ]; - foreach ($propertyValues as $key => $propVal) { - $this->assertIsObject($propVal, "Unable to create the StoragePropertyValue: $field_name, $key"); - } - - // Make sure the values start empty. - $this->assertEquals($this->feature_id, $propertyValues['feature_id']->getValue(), "The $field_name feature_id property should be the feature_id."); - $this->assertTrue(empty($propertyValues['featureprop_id']->getValue()), "The $field_name feature property pkey should not have a value."); - $this->assertTrue(empty($propertyValues['fk_feature_id']->getValue()), "The $field_name feature property feature_id property should not have a value."); - $this->assertTrue(empty($propertyValues['type_id']->getValue()), "The $field_name type_id property should not have a value."); - $this->assertTrue(empty($propertyValues['value']->getValue()), "The $field_name value property should not have a value."); - $this->assertTrue(empty($propertyValues['rank']->getValue()), "The $field_name rank property should not have a value."); - - // Now test ChadoStorage->addTypes() - // param array $types = Array of \Drupal\tripal\TripalStorage\StoragePropertyTypeBase objects. - $chado_storage->addTypes($field_name, $propertyTypes); - $retrieved_types = $chado_storage->getTypes(); - $this->assertIsArray($retrieved_types, "Unable to retrieve the PropertyTypes after adding $field_name."); - // @update to match new format $this->assertCount(8, $retrieved_types, "Did not revieve the expected number of PropertyTypes after adding $field_name."); - - // We also need FieldConfig classes for loading values. - // We're going to create a TripalField and see if that works. - $fieldconfig = new FieldConfigMock(['field_name' => $field_name, 'entity_type' => $this->content_type]); - $fieldconfig->setMock(['label' => $field_label, 'settings' => $storage_settings]); - $chado_storage->addFieldDefinition($field_name, $fieldconfig); - - // Next we actually load the values. - $values[$field_name] = [ 0 => [], 1 => [], 2 => [] ]; - foreach ($propertyTypes as $key => $propType) { - $values[$field_name][0][$key] = [ - 'value' => clone $propertyValues[$key], - ]; - - if ($key != 'feature_id') { - $values[$field_name][1][$key] = [ - 'value' => clone $propertyValues[$key], - ]; - $values[$field_name][2][$key] = [ - 'value' => clone $propertyValues[$key], - ]; - } - } - // We also need to set the featureprop_id for each. - $values[$field_name][0]['featureprop_id']['value']->setValue($this->featureprop_id[0]); - $values[$field_name][1]['featureprop_id']['value']->setValue($this->featureprop_id[1]); - $values[$field_name][2]['featureprop_id']['value']->setValue($this->featureprop_id[2]); - // Now we can try to load the rest of the property. - $success = $chado_storage->loadValues($values); - $this->assertTrue($success, "Loading values after adding $field_name was not success (i.e. did not return TRUE)."); - - // Then we test that the values are now in the types that we passed in. - // All fields should have been loaded, not just our organism one. - $this->assertEquals('test_gene_name', $values['schema__name'][0]['name']['value']->getValue(), 'The gene name value was not loaded properly.'); - // Now test the feature properties were loaded as expected. - // Values: - // - type: note (rdfs:comment), value: "Note 1", rank: 0 - // - type: note (rdfs:comment), value: "Note 2", rank: 2 - // - type: note (rdfs:comment), value: "Note 3", rank: 1 - $this->assertEquals( - "Note 1", $values['rdfs__comment'][0]['value']['value']->getValue(), - 'The delta 0 featureprop.value was not loaded properly.' - ); - $this->assertEquals( - "Note 3", $values['rdfs__comment'][1]['value']['value']->getValue(), - 'The delta 1 featureprop.value was not loaded properly.' - ); - $this->assertEquals( - "Note 2", $values['rdfs__comment'][2]['value']['value']->getValue(), - 'The delta 2 featureprop.value was not loaded properly.' - ); - $note_type_id = $this->getCvtermID('rdfs', 'comment'); - foreach([0,1,2] as $delta) { - $this->assertEquals( - $note_type_id, $values['rdfs__comment'][$delta]['type_id']['value']->getValue(), - "The type_id of the delta $delta note was not loaded properly." - ); - $this->assertEquals( - $this->feature_id, $values['rdfs__comment'][$delta]['fk_feature_id']['value']->getValue(), - "The featureprop.feature_id of the delta $delta note was not loaded properly." - ); - $this->assertEquals( - $delta, $values['rdfs__comment'][$delta]['rank']['value']->getValue(), - "The featureprop.rank of the delta $delta note was not loaded properly." - ); - } - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // -- Single value, multi-property field - // Stored in feature.organism_id; Term: obi:organism. - // Value: genus: Oryza, species: sativa, common_name: rice, - // abbreviation: O.sativa, infraspecific_name: Japonica, - // type: species_group (TAXRANK:0000010), comment: 'This is rice' - $field_name = 'chado_organism_default'; - $field_label = 'Organism'; - $field_type = 'ChadoOrganismDefault'; - $field_term_string = 'obi:organism'; - $chado_table = 'feature'; - $chado_column = 'organism_id'; - $storage_settings = [ - 'storage_plugin_id' => 'chado_storage', - 'storage_plugin_settings' => [ - 'base_table' => $chado_table, - ], - ]; - - // Testing the Property Type class creation. - $base_table = $chado_table; - $propertyTypes = [ - 'feature_id' => new ChadoIntStoragePropertyType($this->content_type, $field_name, 'feature_id', 'SIO:000729', [ - 'action' => 'store_id', - 'drupal_store' => TRUE, - 'chado_table' => $base_table, - 'chado_column' => 'feature_id' - ]), - 'organism_id' => new ChadoIntStoragePropertyType($this->content_type, $field_name, 'organism_id', 'OBI:0100026', [ - 'action' => 'store', - 'chado_table' => $base_table, - 'chado_column' => 'organism_id', - ]), - 'label' => new ChadoVarCharStoragePropertyType($this->content_type, $field_name, 'label', 'rdfs:label', 255, [ - 'action' => 'replace', - 'template' => "[genus] [species] [infraspecific_type] [infraspecific_name]", - ]), - 'genus' => new ChadoVarCharStoragePropertyType($this->content_type, $field_name, 'genus', 'TAXRANK:0000005', 255, [ - 'action' => 'read_value', - 'path' => $base_table . '.organism_id>organism.organism_id', - 'chado_column' => 'genus' - ]), - 'species' => new ChadoVarCharStoragePropertyType($this->content_type, $field_name, 'species', 'TAXRANK:0000006', 255, [ - 'action' => 'read_value', - 'path' => $base_table . '.organism_id>organism.organism_id', - 'chado_column' => 'species' - ]), - 'infraspecific_name' => new ChadoVarCharStoragePropertyType($this->content_type, $field_name, 'infraspecific_name', 'TAXRANK:0000045', 255, [ - 'action' => 'read_value', - 'path' => $base_table . '.organism_id>organism.organism_id', - 'chado_column' => 'infraspecific_name', - ]), - 'infraspecific_type'=> new ChadoIntStoragePropertyType($this->content_type, $field_name, 'infraspecific_type', 'local:infraspecific_type', [ - 'action' => 'read_value', - 'path' => $base_table . '.organism_id>organism.organism_id;organism.type_id>cvterm.cvterm_id', - 'chado_column' => 'name', - 'as' => 'infraspecific_type_name' - ]) - ]; - foreach ($propertyTypes as $key => $propType) { - $this->assertIsObject($propType, "Unable to create the *StoragePropertyType: $field_name, $key"); - } - - // Testing the Property Value class creation. - $propertyValues = [ - 'feature_id' => new StoragePropertyValue($this->content_type, $field_name, 'feature_id', 'SIO:000729', $this->content_entity_id, $this->feature_id), - 'organism_id' => new StoragePropertyValue($this->content_type, $field_name, 'organism_id', 'OBI:0100026', $this->content_entity_id), - 'label' => new StoragePropertyValue($this->content_type, $field_name, 'label', 'rdfs:label', $this->content_entity_id), - 'genus' => new StoragePropertyValue($this->content_type, $field_name, 'genus', 'TAXRANK:0000005', $this->content_entity_id), - 'species' => new StoragePropertyValue($this->content_type, $field_name, 'species', 'TAXRANK:0000006', $this->content_entity_id), - 'infraspecific_name' => new StoragePropertyValue($this->content_type, $field_name, 'infraspecific_name', 'TAXRANK:0000045', $this->content_entity_id), - 'infraspecific_type'=> new StoragePropertyValue($this->content_type, $field_name, 'infraspecific_type', 'local:infraspecific_type', $this->content_entity_id) - ]; - foreach ($propertyValues as $key => $propVal) { - $this->assertIsObject($propVal, "Unable to create the StoragePropertyValue: $field_name, $key"); - } - - // Make sure the values start empty. - $this->assertEquals($this->feature_id, $propertyValues['feature_id']->getValue(), "The $field_name feature_id property should be the feature_id."); - $this->assertTrue(empty($propertyValues['organism_id']->getValue()), "The $field_name value property should not have a value."); - $this->assertTrue(empty($propertyValues['label']->getValue()), "The $field_name label property should not have a value."); - $this->assertTrue(empty($propertyValues['genus']->getValue()), "The $field_name genus property should not have a value."); - $this->assertTrue(empty($propertyValues['species']->getValue()), "The $field_name species property should not have a value."); - $this->assertTrue(empty($propertyValues['infraspecific_name']->getValue()), "The $field_name infraspecific_name property should not have a value."); - $this->assertTrue(empty($propertyValues['infraspecific_type']->getValue()), "The $field_name infraspecific_type property should not have a value."); - - // Now test ChadoStorage->addTypes() - // param array $types = Array of \Drupal\tripal\TripalStorage\StoragePropertyTypeBase objects. - $chado_storage->addTypes($field_name, $propertyTypes); - $retrieved_types = $chado_storage->getTypes(); - $this->assertIsArray($retrieved_types, "Unable to retrieve the PropertyTypes after adding $field_name."); - // @update to match new format $this->assertCount(15, $retrieved_types, "Did not revieve the expected number of PropertyTypes after adding $field_name."); - - // We also need FieldConfig classes for loading values. - // We're going to create a TripalField and see if that works. - $fieldconfig = new FieldConfigMock(['field_name' => $field_name, 'entity_type' => $this->content_type]); - $fieldconfig->setMock(['label' => $field_label, 'settings' => $storage_settings]); - $chado_storage->addFieldDefinition($field_name, $fieldconfig); - - // Next we actually load the values. - $values[$field_name] = [ 0 => [] ]; - foreach ($propertyValues as $key => $propValue) { - $values[$field_name][0][$key] = [ - 'value' => $propValue, - ]; - } - $success = $chado_storage->loadValues($values); - $this->assertTrue($success, "Loading values after adding $field_name was not success (i.e. did not return TRUE)."); - - // Then we test that the values are now in the types that we passed in. - // All fields should have been loaded, not just our organism one. - $this->assertEquals( - 'test_gene_name', $values['schema__name'][0]['name']['value']->getValue(), - 'The gene name value was not loaded properly.' - ); - $this->assertEquals( - "Note 1", $values['rdfs__comment'][0]['value']['value']->getValue(), - 'The delta 0 featureprop.value was not loaded properly.' - ); - $this->assertEquals( - "Note 3", $values['rdfs__comment'][1]['value']['value']->getValue(), - 'The delta 1 featureprop.value was not loaded properly.' - ); - $this->assertEquals( - "Note 2", $values['rdfs__comment'][2]['value']['value']->getValue(), - 'The delta 2 featureprop.value was not loaded properly.' - ); - // Now test the organism values were loaded as expected. - // Value: genus: Oryza, species: sativa, common_name: rice, - // abbreviation: O.sativa, infraspecific_name: Japonica, - // type: species_group (TAXRANK:0000010), comment: 'This is rice' - $this->assertEquals($this->organism_id, $values['chado_organism_default'][0]['organism_id']['value']->getValue(), 'The organism value was not loaded properly.'); - $this->assertEquals('Oryza', $values['chado_organism_default'][0]['genus']['value']->getValue(), 'The organism genus was not loaded properly.'); - $this->assertEquals('sativa', $values['chado_organism_default'][0]['species']['value']->getValue(), 'The organism species was not loaded properly.'); - $this->assertEquals('Japonica', $values['chado_organism_default'][0]['infraspecific_name']['value']->getValue(), 'The organism infraspecific name was not loaded properly.'); - $this->assertEquals('species_group', $values['chado_organism_default'][0]['infraspecific_type']['value']->getValue(), 'The organism infraspecific type was not loaded properly.'); - $this->assertEquals("Oryza sativa species_group Japonica", $values['chado_organism_default'][0]['label']['value']->getValue(), 'The organism label was not loaded properly.'); - } -} From 656ec3a3ca158a6ddde8a3caa028793529b1e6a5 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Fri, 20 Oct 2023 10:30:44 -0600 Subject: [PATCH 36/74] Ensure reverse lookup is not tried for replace/function actions. --- tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index 54120bb70..9a72f1ba5 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -624,6 +624,11 @@ protected function setRecordIds(&$values, $records) { } $action = $prop_storage_settings['action']; + // Quickly skip any property whose action is not focused on keys. + if (!in_array($action, ['store_id', 'store_pkey', 'store_link'])) { + continue; + } + // Get the base table information and use it as the default for if // a chado_table is not specified (as in the case of single value fields). $chado_table = $storage_plugin_settings['base_table']; @@ -1881,7 +1886,8 @@ protected function getTableAliasForChadoTable($field_name, $property_key, $chado } } - print "\nWe could not reverse lookup for $field_name > $property_key : $chado_table. Reverse Mapping: " . print_r($this->reverse_alias_mapping, TRUE) . "Forward Mapping: " . print_r($this->table_alias_mapping, TRUE); + $this->logger->warning('ChadoStorage could not find the table alias for the requested chado table. Specifically, we were trying to look up the alias for @table for the field @field, property @property.', + ['@table' => $chado_table, '@field' => $field_name, '@property' => $property_key]); return NULL; } From 0afbb76d78c5be1cbeed94d2333229d27f09a9f3 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Fri, 20 Oct 2023 11:40:13 -0600 Subject: [PATCH 37/74] Simplify test by defining the fields in a YAML format. --- .../ChadoStorageActions-FieldDefinitions.yml | 64 +++++++++++++++++++ .../ChadoStorage/ChadoStorageActionsTest.php | 62 ++---------------- .../src/Traits/ChadoStorageTestTrait.php | 34 ++++++++++ 3 files changed, 102 insertions(+), 58 deletions(-) create mode 100644 tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml new file mode 100644 index 000000000..1903b8c06 --- /dev/null +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml @@ -0,0 +1,64 @@ +## +## Used to provide file/property definitions for the tests in +## ChadoStorageActionsTest.php +## +## The format is as follows: +## [action to be tested]: +## [field name]: +## field_name: [field name] +## base_table: [base table] +## properties: +## [property key]: +## propertyType class: [full class name + namespace] +## action: [action] +## [additional key/value pairs associated with the action] + +read_value: + # The core field used to test the read action. + test_read: + field_name: 'test_read' + base_table: 'project' + properties: + record_id: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_id' + chado_table: 'project' + chado_column: 'project_id' + name_read: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'read_value' + chado_table: 'project' + chado_column: 'name' + # A field which focuses on storing the same fields as the read field above. + # This is added to ensure there is no conflict between having two fields + # accessing the same column with different action types. + other_field_store: + field_name: 'other_field_store' + base_table: 'project' + properties: + record_id: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_id' + chado_table: 'project' + chado_column: 'project_id' + name_store: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'store' + chado_table: 'project' + chado_column: 'name' + # This is another read-focused field focused on the same as columns. + # This is here to ensure there are no conflicts with two fields reading the same value. + other_field_read: + field_name: 'other_field_read' + base_table: 'project' + properties: + record_id: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_id' + chado_table: 'project' + chado_column: 'project_id' + name_read_again: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'read_value' + chado_table: 'project' + chado_column: 'name' diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActionsTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActionsTest.php index 08dba7028..6038c7356 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActionsTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActionsTest.php @@ -25,6 +25,8 @@ class ChadoStorageActionsTest extends ChadoTestKernelBase { // with fields specific to that test. protected $fields = []; + protected $yaml_file = __DIR__ . "/ChadoStorageActions-FieldDefinitions.yml"; + /** * {@inheritdoc} */ @@ -64,64 +66,8 @@ protected function setUp() :void { */ public function testReadValueAction() { - // This is the field we are actually testing. - $this->fields['test_read'] = [ - 'field_name' => 'test_read', - 'base_table' => 'project', - 'properties' => [ - 'record_id' => [ - 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', - 'action' => 'store_id', - 'chado_table' => 'project', - 'chado_column' => 'project_id' - ], - 'name_read' => [ - 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType', - 'action' => 'read_value', - 'chado_table' => 'project', - 'chado_column' => 'name' - ], - ], - ]; - // This is another field (STORE) which we want to ensure there are no conflicts with. - $this->fields['other_field_store'] = [ - 'field_name' => 'other_field_store', - 'base_table' => 'project', - 'properties' => [ - 'record_id' => [ - 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', - 'action' => 'store_id', - 'chado_table' => 'project', - 'chado_column' => 'project_id' - ], - 'name_store' => [ - 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType', - 'action' => 'store', - 'chado_table' => 'project', - 'chado_column' => 'name' - ], - ], - ]; - // This is another field (READ) which we want to ensure there are no conflicts with. - $this->fields['other_field_read'] = [ - 'field_name' => 'other_field_read', - 'base_table' => 'project', - 'properties' => [ - 'record_id' => [ - 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', - 'action' => 'store_id', - 'chado_table' => 'project', - 'chado_column' => 'project_id' - ], - 'name_read_again' => [ - 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType', - 'action' => 'read_value', - 'chado_table' => 'project', - 'chado_column' => 'name' - ], - ], - ]; - // Needed to ensure these fields are added to the storage arrays e.g. field config. + // Set the fields for this test and then re-populate the storage arrays. + $this->setFieldsFromYaml($this->yaml_file, 'read_value'); $this->cleanChadoStorageValues(); // Test Case: Insert valid values when they do not yet exist in Chado. diff --git a/tripal_chado/tests/src/Traits/ChadoStorageTestTrait.php b/tripal_chado/tests/src/Traits/ChadoStorageTestTrait.php index 7c40d1388..cd8c11653 100644 --- a/tripal_chado/tests/src/Traits/ChadoStorageTestTrait.php +++ b/tripal_chado/tests/src/Traits/ChadoStorageTestTrait.php @@ -6,6 +6,8 @@ use Drupal\tripal\TripalStorage\StoragePropertyValue; use Drupal\tripal\TripalStorage\StoragePropertyTypeBase; +use Symfony\Component\Yaml\Yaml; + /** * Provides functions and member variables to be used when testing Chado Storage. * This allows for less duplication of setup and more focus on the particular @@ -729,4 +731,36 @@ public function debugChadoStorageTestTraitArrays() { print "\n\n"; } + + /** + * Allows you to set the 'fields' by specifying the top level key of a YAML file. + * + * @param string $yaml_file + * The full path to a yaml file which follows the format descripbed above. + * @param string $top_level_key + * The top level key in the yaml file which contains the fields you would + * like to set. + */ + public function setFieldsFromYaml($yaml_file, $top_level_key) { + + if (!file_exists($yaml_file)) { + throw new \Exception("Cannot open YAML file $yaml_file in order to set the fields for testing chadostorage."); + } + + $file_contents = file_get_contents($yaml_file); + if (empty($file_contents)) { + throw new \Exception("Unable to retrieve contents for YAML file $yaml_file in order to set the fields for testing chadostorage."); + } + + $yaml_data = Yaml::parse($file_contents); + if (empty($yaml_data)) { + throw new \Exception("Unable to parse YAML file $yaml_file in order to set the fields for testing chadostorage."); + } + + if (!array_key_exists($top_level_key, $yaml_data)) { + throw new \Exception("The Top level key $top_level_key that you provided does not exist in the parsed YAML file: $yaml_file."); + } + + $this->fields = $yaml_data[$top_level_key]; + } } From a05c90376d748babfefac09e1a72fe3fcd4b2d97 Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Mon, 23 Oct 2023 14:55:07 -0600 Subject: [PATCH 38/74] Add testing for multiple property fields. --- .../ChadoLinkerPropertyDefaultTest.php | 375 +++++++++++++++--- 1 file changed, 310 insertions(+), 65 deletions(-) diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php index 007197133..15719019c 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php @@ -46,7 +46,7 @@ class ChadoLinkerPropertyDefaultTest extends ChadoTestKernelBase { 'base_table' => 'feature', 'properties' => [ // Keeps track of the feature record our hypothetical field cares about. - 'A_record_id' => [ + 'record_id' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store_id', 'drupal_store' => TRUE, @@ -54,47 +54,47 @@ class ChadoLinkerPropertyDefaultTest extends ChadoTestKernelBase { 'chado_column' => 'feature_id' ], // Store the primary key for the prop table. - 'A_prop_id' => [ + 'prop_id' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store_pkey', 'chado_table' => 'featureprop', - 'chado_table_alias' => 'featureprop_rdfstype', + 'chado_table_alias' => 'featureprop_A', 'chado_column' => 'featureprop_id', ], // Generate `JOIN {featureprop} ON feature.feature_id = featureprop.feature_id` // Will also store the feature.feature_id so no need for drupal_store => TRUE. - 'A_linker_id' => [ + 'linker_id' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store_link', 'left_table' => 'feature', 'left_table_id' => 'feature_id', 'right_table' => 'featureprop', - 'right_table_alias' => 'featureprop_rdfstype', + 'right_table_alias' => 'featureprop_A', 'right_table_id' => 'feature_id' ], // Now we are going to store all the core columns of the featureprop table to // ensure we can meet the unique and not null requirements of the table. - 'A_type_id' => [ + 'type_id' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store', 'chado_table' => 'featureprop', - 'chado_table_alias' => 'featureprop_rdfstype', + 'chado_table_alias' => 'featureprop_A', 'chado_column' => 'type_id' ], - 'A_value' => [ + 'value' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoTextStoragePropertyType', 'action' => 'store', 'chado_table' => 'featureprop', - 'chado_table_alias' => 'featureprop_rdfstype', + 'chado_table_alias' => 'featureprop_A', 'chado_column' => 'value', 'delete_if_empty' => TRUE, 'empty_value' => '' ], - 'A_rank' => [ + 'rank' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store', 'chado_table' => 'featureprop', - 'chado_table_alias' => 'featureprop_rdfstype', + 'chado_table_alias' => 'featureprop_A', 'chado_column' => 'rank' ], ], @@ -103,43 +103,50 @@ class ChadoLinkerPropertyDefaultTest extends ChadoTestKernelBase { 'field_name' => 'testpropertyfieldB', 'base_table' => 'feature', 'properties' => [ - 'B_record_id' => [ + 'record_id' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store_id', 'drupal_store' => TRUE, 'chado_table' => 'feature', 'chado_column' => 'feature_id' ], - 'B_prop_id' => [ + 'prop_id' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store_pkey', 'chado_table' => 'featureprop', + 'chado_table_alias' => 'featureprop_B', 'chado_column' => 'featureprop_id', ], - 'B_linker_id' => [ + 'linker_id' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store_link', - 'chado_table' => 'featureprop', - 'chado_column' => 'feature_id' + 'left_table' => 'feature', + 'left_table_id' => 'feature_id', + 'right_table' => 'featureprop', + 'right_table_alias' => 'featureprop_B', + 'right_table_id' => 'feature_id' ], - 'B_type_id' => [ + 'type_id' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store', 'chado_table' => 'featureprop', + 'chado_table_alias' => 'featureprop_B', 'chado_column' => 'type_id' ], - 'B_value' => [ + 'value' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoTextStoragePropertyType', 'action' => 'store', 'chado_table' => 'featureprop', + 'chado_table_alias' => 'featureprop_B', 'chado_column' => 'value', 'delete_if_empty' => TRUE, 'empty_value' => '' ], - 'B_rank' => [ + 'rank' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store', 'chado_table' => 'featureprop', + 'chado_table_alias' => 'featureprop_B', 'chado_column' => 'rank' ], ], @@ -178,32 +185,32 @@ class ChadoLinkerPropertyDefaultTest extends ChadoTestKernelBase { 'field_name' => 'testpropertyfieldABackwardsCompatible', 'base_table' => 'feature', 'properties' => [ - 'A_record_id' => [ + 'record_id' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store_id', 'drupal_store' => TRUE, 'chado_table' => 'feature', 'chado_column' => 'feature_id' ], - 'A_prop_id' => [ + 'prop_id' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store_pkey', 'chado_table' => 'featureprop', 'chado_column' => 'featureprop_id', ], - 'A_linker_id' => [ + 'linker_id' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store_link', 'chado_table' => 'featureprop', 'chado_column' => 'feature_id' ], - 'A_type_id' => [ + 'type_id' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store', 'chado_table' => 'featureprop', 'chado_column' => 'type_id' ], - 'A_value' => [ + 'value' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoTextStoragePropertyType', 'action' => 'store', 'chado_table' => 'featureprop', @@ -211,7 +218,7 @@ class ChadoLinkerPropertyDefaultTest extends ChadoTestKernelBase { 'delete_if_empty' => TRUE, 'empty_value' => '' ], - 'A_rank' => [ + 'rank' => [ 'propertyType class' => 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType', 'action' => 'store', 'chado_table' => 'featureprop', @@ -244,7 +251,7 @@ protected function setUp() :void { $this->setUpChadoStorageTestEnviro(); // Create the organism record for use with the feature table. - $infra_type_id = $this->getCvtermID('TAXRANK', '0000010'); + $infrtype_id = $this->getCvtermID('TAXRANK', '0000010'); $query = $this->chado_connection->insert('1:organism'); $query->fields([ 'genus' => 'Tripalus', @@ -252,7 +259,7 @@ protected function setUp() :void { 'common_name' => 'Tripal', 'abbreviation' => 'T. databasica', 'infraspecific_name' => 'postgresql', - 'type_id' => $infra_type_id, + 'type_id' => $infrtype_id, 'comment' => 'This is fake organism specifically for testing purposes.' ]); $this->organism_id = $query->execute(); @@ -267,6 +274,7 @@ public function provideSinglePropFieldNames() { ['testpropertyfieldA'] ]; } + /** * Testing ChadoStorage on single property field with multiple values. * @@ -290,28 +298,28 @@ public function testCRUDForSinglePropField($prop_field_name) { $insert_values = [ $prop_field_name => [ [ - 'A_record_id' => NULL, - 'A_prop_id' => NULL, - 'A_linker_id' => NULL, - 'A_type_id' => $rdfs_comment_cvtermID, - 'A_value' => 'Note 1', - 'A_rank' => 0, + 'record_id' => NULL, + 'prop_id' => NULL, + 'linker_id' => NULL, + 'type_id' => $rdfs_comment_cvtermID, + 'value' => 'Note 1', + 'rank' => 0, ], [ - 'A_record_id' => NULL, - 'A_prop_id' => NULL, - 'A_linker_id' => NULL, - 'A_type_id' => $rdfs_comment_cvtermID, - 'A_value' => 'Note 2', - 'A_rank' => 1, + 'record_id' => NULL, + 'prop_id' => NULL, + 'linker_id' => NULL, + 'type_id' => $rdfs_comment_cvtermID, + 'value' => 'Note 2', + 'rank' => 1, ], [ - 'A_record_id' => NULL, - 'A_prop_id' => NULL, - 'A_linker_id' => NULL, - 'A_type_id' => $rdfs_comment_cvtermID, - 'A_value' => 'Note 3', - 'A_rank' => 2, + 'record_id' => NULL, + 'prop_id' => NULL, + 'linker_id' => NULL, + 'type_id' => $rdfs_comment_cvtermID, + 'value' => 'Note 3', + 'rank' => 2, ] ], 'testotherfeaturefield' => [ @@ -372,12 +380,12 @@ public function testCRUDForSinglePropField($prop_field_name) { $query = $this->chado_connection->select('1:featureprop', 'prop') ->fields('prop', ['featureprop_id', 'feature_id', 'type_id', 'value', 'rank']) ->condition('feature_id', $feature_id, '=') - ->condition('type_id', $expected['A_type_id']) - ->condition('rank', $expected['A_rank']) + ->condition('type_id', $expected['type_id']) + ->condition('rank', $expected['rank']) ->execute(); $records = $query->fetchAll(); $this->assertCount(1, $records, "We expected to get exactly one record for:" . print_r($expected, TRUE)); - $this->assertEquals($expected['A_value'], $records[0]->value, "We did not get the value we expected using the unique key." . print_r($expected, TRUE)); + $this->assertEquals($expected['value'], $records[0]->value, "We did not get the value we expected using the unique key." . print_r($expected, TRUE)); $varname = 'prop' . $delta; $$varname = $records[0]; @@ -395,19 +403,19 @@ public function testCRUDForSinglePropField($prop_field_name) { $load_values = [ $prop_field_name => [ [ - 'A_record_id' => $feature_id, - 'A_prop_id' => $prop0->featureprop_id, - 'A_linker_id' => $feature_id, + 'record_id' => $feature_id, + 'prop_id' => $prop0->featureprop_id, + 'linker_id' => $feature_id, ], [ - 'A_record_id' => $feature_id, - 'A_prop_id' => $prop1->featureprop_id, - 'A_linker_id' => $feature_id, + 'record_id' => $feature_id, + 'prop_id' => $prop1->featureprop_id, + 'linker_id' => $feature_id, ], [ - 'A_record_id' => $feature_id, - 'A_prop_id' => $prop2->featureprop_id, - 'A_linker_id' => $feature_id, + 'record_id' => $feature_id, + 'prop_id' => $prop2->featureprop_id, + 'linker_id' => $feature_id, ] ], 'testotherfeaturefield' => [ @@ -435,17 +443,17 @@ public function testCRUDForSinglePropField($prop_field_name) { $expected = $$varname; $this->assertEquals( $expected->type_id, - $retrieved['A_type_id']['value']->getValue(), + $retrieved['type_id']['value']->getValue(), "The type for delta $delta did not match the one we retrieved from chado after insert." ); $this->assertEquals( $expected->value, - $retrieved['A_value']['value']->getValue(), + $retrieved['value']['value']->getValue(), "The value for delta $delta did not match the one we retrieved from chado after insert." ); $this->assertEquals( $expected->rank, - $retrieved['A_rank']['value']->getValue(), + $retrieved['rank']['value']->getValue(), "The rank for delta $delta did not match the one we retrieved from chado after insert." ); } @@ -465,8 +473,8 @@ public function testCRUDForSinglePropField($prop_field_name) { } // We then change a few non key related values... - $update_values[$prop_field_name][1]['A_value'] = 'Changed Note to be more informative.'; - $update_values[$prop_field_name][2]['A_value'] = 'Something completely different. Not even a note at all.'; + $update_values[$prop_field_name][1]['value'] = 'Changed Note to be more informative.'; + $update_values[$prop_field_name][2]['value'] = 'Something completely different. Not even a note at all.'; ob_start(); $this->chadoStorageTestUpdateValues($update_values); $printed_output = ob_get_clean(); @@ -494,12 +502,12 @@ public function testCRUDForSinglePropField($prop_field_name) { $query = $this->chado_connection->select('1:featureprop', 'prop') ->fields('prop', ['featureprop_id', 'feature_id', 'type_id', 'value', 'rank']) ->condition('feature_id', $feature_id, '=') - ->condition('type_id', $expected['A_type_id']) - ->condition('rank', $expected['A_rank']) + ->condition('type_id', $expected['type_id']) + ->condition('rank', $expected['rank']) ->execute(); $records = $query->fetchAll(); $this->assertCount(1, $records, "We expected to get exactly one record for:" . print_r($expected, TRUE)); - $this->assertEquals($expected['A_value'], $records[0]->value, "We did not get the value we expected using the unique key." . print_r($expected, TRUE)); + $this->assertEquals($expected['value'], $records[0]->value, "We did not get the value we expected using the unique key." . print_r($expected, TRUE)); } // Test Case: Delete values in Chado using ChadoStorage. @@ -508,4 +516,241 @@ public function testCRUDForSinglePropField($prop_field_name) { // NOT YET IMPLEMENTED IN CHADOSTORAGE. } + + /** + * Data Provider: Provide values for testing multiple property fields. + */ + public function provideMultiplePropFields() { + return [ + [ + 'fields' => [ + 'testpropertyfieldA' => [ + 'type' => ['rdfs', 'comment'], + 'value_prefix' => 'RDFS Comment #', + ], + 'testpropertyfieldB' => [ + 'type' => ['schema', 'comment'], + 'value_prefix' => 'Schema Comment #', + ], + ], + ], + ]; + } + + /** + * Testing ChadoStorage on multiple property fields, each with multiple values. + * + * @dataProvider provideMultiplePropFields + * + * Test Cases: + * - Both fields create values in Chado when they don't yet exists (similar to creating Tripal Content) + * - Both fields have changed values to be updated in chado (update the page and change both fields) + * - Load tested after create and update. + * + * Focus on ensuring that the values from one field are in different chado records + * than those from the other field. + */ + public function testCRUDForMultiplePropFields($prop_field_settings) { + + $prop_fields = array_keys($prop_field_settings); + + // Get Terms + foreach ($prop_field_settings as $field_name => $settings) { + $prop_field_settings[$field_name]['type_id'] = $this->getCvtermID($settings['type'][0], $settings['type'][1]); + $this->assertIsNumeric($prop_field_settings[$field_name]['type_id'], + "Unable to retrieve the type for $field_name based on a type of " . $settings['type'][0] . ':' . $settings['type'][1] . '.'); + } + $gene_cvtermID = $this->getCvtermID('SO', '0000704'); + + // Test Case: Insert valid values when they do not yet exist in Chado. + // --------------------------------------------------------- + // First add values for the otherfield. + $insert_values = [ + 'testotherfeaturefield' => [ + [ + 'feature_type' => $gene_cvtermID, + 'feature_organism' => $this->organism_id, + 'feature_uname' => 'testGene4PropTableTest', + ] + ], + ]; + // Now use the settings to generate values for the property fields. + $max_delta = 4; + foreach ($prop_field_settings as $field_name => $settings) { + // We want multiple values for each field. + foreach([0,1,2,3] as $delta) { + $insert_values[$field_name][$delta] = [ + 'record_id' => NULL, + 'prop_id' => NULL, + 'linker_id' => NULL, + 'type_id' => $settings['type_id'], + 'value' => $settings['value_prefix'] . $delta, + 'rank' => $delta, + ]; + } + } + // @debug print_r($insert_values); + $this->chadoStorageTestInsertValues($insert_values); + + // Check that the base feature record was created in the database as expected. + // Note: makes some assumptions based on knowing the data provider for + // better readability of the tests. + $field_name = 'testotherfeaturefield'; + $query = $this->chado_connection->select('1:feature', 'f') + ->fields('f', ['feature_id', 'type_id', 'organism_id', 'uniquename']) + ->execute(); + $records = $query->fetchAll(); + $this->assertCount(1, $records, + "There should only be a single feature record created by our storage properties."); + $record = $records[0]; + $record_expect = $insert_values[$field_name][0]; + $this->assertIsObject($record, + "The returned feature record should be an object."); + $this->assertEquals($record_expect['feature_type'], $record->type_id, + "The feature record should have the type we set in our storage properties."); + $this->assertEquals($record_expect['feature_organism'], $record->organism_id, + "The feature record should have the organism we set in our storage properties."); + $this->assertEquals($record_expect['feature_uname'], $record->uniquename, + "The feature record should have the unique name we set in our storage properties."); + $feature_id = $record->feature_id; + + // Also check that there are only the expected number of records + // in the featureprop table. + $query = $this->chado_connection->select('1:featureprop', 'prop') + ->fields('prop', ['featureprop_id', 'feature_id', 'type_id', 'value', 'rank']) + ->execute(); + $all_featureprop_records = $query->fetchAll(); + $this->assertCount(8, $all_featureprop_records, + "There were not the number of records in the featureprop table that we were expected. These are the records found in the database: " . print_r($all_featureprop_records, TRUE)); + + // @debug print_r($all_featureprop_records); + + // Check that the featureprop records were created in the database as expected. + // We use the unique key to select this particular value in order to + // ensure it is here and there is one one. + foreach ($prop_fields as $prop_field_name) { + foreach ($insert_values[$prop_field_name] as $delta => $expected) { + $query = $this->chado_connection->select('1:featureprop', 'prop') + ->fields('prop', ['featureprop_id', 'feature_id', 'type_id', 'value', 'rank']) + ->condition('feature_id', $feature_id, '=') + ->condition('type_id', $expected['type_id']) + ->condition('rank', $expected['rank']) + ->execute(); + $records = $query->fetchAll(); + $this->assertCount(1, $records, "We expected to get exactly one record for:" . print_r($expected, TRUE)); + $this->assertEquals($expected['value'], $records[0]->value, "We did not get the value we expected using the unique key." . print_r($expected, TRUE)); + + $varname = 'prop_' . $prop_field_name . $delta; + $$varname = $records[0]; + } + } + + + // Test Case: Load values existing in Chado. + // --------------------------------------------------------- + // First we want to reset all the chado storage arrays to ensure we are + // doing a clean test. The values will purposefully remain in Chado but the + // Property Types, Property Values and Data Values will be built from scratch. + $this->cleanChadoStorageValues(); + + // For loading only the store id/pkey/link items should be populated. + $load_values = [ + 'testotherfeaturefield' => [ + [ + 'record_id' => $feature_id, + ] + ], + ]; + foreach ($prop_field_settings as $prop_field_name => $settings) { + foreach([0,1,2,3] as $delta) { + $varname = 'prop_' . $prop_field_name . $delta; + $load_values[$prop_field_name][$delta] = [ + 'record_id' => $feature_id, + 'prop_id' => $$varname->featureprop_id, + 'linker_id' => $feature_id, + ]; + } + } + $retrieved_values = $this->chadoStorageTestLoadValues($load_values); + + // Now test that the additional values have been loaded. + // @debug $this->debugChadoStorageTestTraitArrays(); + foreach ($prop_fields as $prop_field_name) { + foreach([0,1,2,3] as $delta) { + $retrieved = $retrieved_values[$prop_field_name][$delta]; + $varname = 'prop_' . $prop_field_name . $delta; + $expected = $$varname; + $this->assertEquals( + $expected->type_id, + $retrieved['type_id']['value']->getValue(), + "The type for delta $delta did not match the one we retrieved from chado after insert." + ); + $this->assertEquals( + $expected->value, + $retrieved['value']['value']->getValue(), + "The value for delta $delta did not match the one we retrieved from chado after insert." + ); + $this->assertEquals( + $expected->rank, + $retrieved['rank']['value']->getValue(), + "The rank for delta $delta did not match the one we retrieved from chado after insert." + ); + } + } + + + // Test Case: Update values in Chado using ChadoStorage. + // --------------------------------------------------------- + // When updating we need all the store id/pkey/link records + // and all values of the other properties. + // array_merge alone seems not to be sufficient + $update_values = $insert_values; + foreach ($load_values as $field_name => $tmp) { + foreach ($tmp as $delta => $id_values) { + foreach ($id_values as $key => $value) { + $update_values[$field_name][$delta][$key] = $value; + } + } + } + + // We then change a few non key related values... + $changed_update_values = $update_values; + $changed_update_values[$prop_fields[0]][1]['value'] = 'Changed Note to be more informative.'; + $changed_update_values[$prop_fields[1]][3]['value'] = 'Something completely different. Not even a note at all.'; + $this->chadoStorageTestUpdateValues($update_values); + + // Now we check chado to see if these values were changed... + // Still the expected number of records in the featureprop table? + $query = $this->chado_connection->select('1:featureprop', 'prop') + ->fields('prop', ['feature_id', 'type_id', 'value', 'rank']) + ->execute(); + $all_featureprop_records = $query->fetchAll(); + $this->assertCount(8, $all_featureprop_records, + "There were more records then we were expecting in the featureprop table: " . print_r($all_featureprop_records, TRUE)); + + // Check that the featureprop records were created in the database as expected. + // We use the unique key to select this particular value in order to + // ensure it is here and there is one one. + foreach ($prop_fields as $prop_field_name) { + foreach ($insert_values[$prop_field_name] as $delta => $expected) { + $query = $this->chado_connection->select('1:featureprop', 'prop') + ->fields('prop', ['featureprop_id', 'feature_id', 'type_id', 'value', 'rank']) + ->condition('feature_id', $feature_id, '=') + ->condition('type_id', $expected['type_id']) + ->condition('rank', $expected['rank']) + ->execute(); + $records = $query->fetchAll(); + $this->assertCount(1, $records, "We expected to get exactly one record for:" . print_r($expected, TRUE)); + $this->assertEquals($expected['value'], $records[0]->value, "We did not get the value we expected using the unique key." . print_r($expected, TRUE)); + + $varname = 'prop_' . $prop_field_name . $delta; + $$varname = $records[0]; + } + } + + // Test Case: Delete values in Chado using ChadoStorage. + // --------------------------------------------------------- + + // NOT YET IMPLEMENTED IN CHADOSTORAGE. + } } From 310be502b7ed472e18f110c656283778e7fe7cfd Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Tue, 24 Oct 2023 11:06:05 -0600 Subject: [PATCH 39/74] Rename read_value test --- ...ageActionsTest.php => ChadoStorageActions_ReadValueTest.php} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/{ChadoStorageActionsTest.php => ChadoStorageActions_ReadValueTest.php} (99%) diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActionsTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php similarity index 99% rename from tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActionsTest.php rename to tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php index 6038c7356..fdeab824a 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActionsTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php @@ -17,7 +17,7 @@ * @group Tripal Chado * @group ChadoStorage */ -class ChadoStorageActionsTest extends ChadoTestKernelBase { +class ChadoStorageActions_ReadValueTest extends ChadoTestKernelBase { use ChadoStorageTestTrait; From 9b3aad4139fe85dc11fb4b8e4108c8c1ae68921c Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Tue, 24 Oct 2023 12:06:55 -0600 Subject: [PATCH 40/74] Add basic test for store_id action. --- .../ChadoStorageActions-FieldDefinitions.yml | 63 +++++++ .../ChadoStorageActions_ReadValueTest.php | 1 + .../ChadoStorageActions_StoreIdTest.php | 158 ++++++++++++++++++ .../src/Traits/ChadoStorageTestTrait.php | 22 ++- 4 files changed, 241 insertions(+), 3 deletions(-) create mode 100644 tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml index 1903b8c06..876637084 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml @@ -13,6 +13,10 @@ ## action: [action] ## [additional key/value pairs associated with the action] + +## Focus: Showing that the read_value action can read a value without any +## conflict with other fields. +## Chado Table: Project read_value: # The core field used to test the read action. test_read: @@ -62,3 +66,62 @@ read_value: action: 'read_value' chado_table: 'project' chado_column: 'name' + +## Focus: Ensure that we can create records by setting this to NULL. Also ensure +## that there are no assumptions that this only be used on our typical set of +## base tables... rather it should work if: +## the chado table for the property = the base_table for the field. +## Chado Table: db +store_id: + test_store_id: + field_name: 'test_store_id' + base_table: 'db' + properties: + random_name: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_id' + chado_table: 'db' + chado_column: 'db_id' + name: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'store' + chado_table: 'db' + chado_column: 'name' + # This field should not work as the store_id is not associated with the base table of the field. + test_non_base_match: + field_name: test_store_id + base_table: cv + properties: + random_name: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_id' + chado_table: 'db' + chado_column: 'db_id' + name: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'store' + chado_table: 'db' + chado_column: 'name' + # Check that the chado table alias setting works on this action. + test_chado_alias: + field_name: 'test_chado_alias' + base_table: 'db' + properties: + random_name: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_id' + chado_table: 'db' + chado_table_alias: 'fred' + chado_column: 'db_id' + name: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'store' + chado_table: 'db' + chado_table_alias: 'fred' + chado_column: 'name' + +store_pkey: + +store_link: + +store: diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php index fdeab824a..115f343a6 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php @@ -16,6 +16,7 @@ * @group Tripal * @group Tripal Chado * @group ChadoStorage + * @group ChadoStorage Actions */ class ChadoStorageActions_ReadValueTest extends ChadoTestKernelBase { diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php new file mode 100644 index 000000000..da8953c88 --- /dev/null +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php @@ -0,0 +1,158 @@ +set('is_a_test_environment', TRUE); + + // We need to mock the logger to test the progress reporting. + $container = \Drupal::getContainer(); + $mock_logger = $this->getMockBuilder(\Drupal\tripal\Services\TripalLogger::class) + ->onlyMethods(['warning']) + ->getMock(); + $mock_logger->method('warning') + ->willReturnCallback(function($message, $context, $options) { + print str_replace(array_keys($context), $context, $message); + return NULL; + }); + $container->set('tripal.logger', $mock_logger); + + $this->setUpChadoStorageTestEnviro(); + } + + /** + * Test the read_value action. + * + * Chado Table: project + * Columns: project_id*, name*, description + * + * Specifically, + * - Ensure that a property with the read_value action has the value set + * - Ensure that a property with the read_value action can't change the value + * - That two fields accessing the same chado column do not conflict + * A. both read_value action for the same column + * B. one read_value and one store for the same column + */ + public function testStoreIdAction() { + + $field_name = 'test_store_id'; + + // Set the fields for this test and then re-populate the storage arrays. + $this->setFieldsFromYaml($this->yaml_file, "store_id.$field_name"); + $this->cleanChadoStorageValues(); + + // Test Case: Insert valid values when they do not yet exist in Chado. + // --------------------------------------------------------- + $insert_values = [ + $field_name => [ + [ + 'random_name' => NULL, + 'name' => 'Something random that is only here because this field is required.', + ], + ], + ]; + $this->chadoStorageTestInsertValues($insert_values); + + // Check that there is now a single db record. + $query = $this->chado_connection->select('1:db', 'db') + ->fields('db', ['db_id', 'name']) + ->condition('db.name', $insert_values[$field_name][0]['name'], '=') + ->execute(); + $records = $query->fetchAll(); + $this->assertIsArray($records, + "We should have been able to select from the record from the db table."); + $this->assertCount(1, $records, + "There should only be a single db with this name"); + + $db_id = $records[0]->db_id; + + // Test Case: Load values existing in Chado. + // --------------------------------------------------------- + // First we want to reset all the chado storage arrays to ensure we are + // doing a clean test. The values will purposefully remain in Chado but the + // Property Types, Property Values and Data Values will be built from scratch. + $this->cleanChadoStorageValues(); + + // For loading only the store id/pkey/link items should be populated. + // Since the id is passed in we're just checking it was set to the value property. + $load_values = [ + $field_name => [ + [ + 'random_name' => $db_id, + 'name' => NULL, + ], + ], + ]; + $retrieved_values = $this->chadoStorageTestLoadValues($load_values); + + // Check that the name in our fields have been loaded. + $retrieved_id = $retrieved_values[$field_name][0]['random_name']['value']->getValue(); + $this->assertEquals($db_id, $retrieved_id, + "The ID we retrieved for the $field_name field did not match the one set with a store_id attribute during insert."); + + // We also check the name to be thorough. + $expected_name = $insert_values[$field_name][0]['name']; + $retrieved_name = $retrieved_values[$field_name][0]['name']['value']->getValue(); + $this->assertEquals($expected_name, $retrieved_name, + "The name we retrieved for the $field_name field did not match the one set with a store attribute during insert."); + + // Test Case: Update values in Chado using ChadoStorage. + // --------------------------------------------------------- + // When updating we need all the store id/pkey/link records + // and all values of the other properties. + $update_values = [ + $field_name => [ + [ + 'random_name' => $db_id, + 'name' => 'Something random that is only here because this field is required.', + ], + ], + ]; + + // Let's test this without changing anything. + $this->chadoStorageTestUpdateValues($update_values); + + // Check that there is still only a single db record with this name. + $query = $this->chado_connection->select('1:db', 'db') + ->fields('db', ['db_id', 'name']) + ->condition('db.name', $update_values[$field_name][0]['name'], '=') + ->execute(); + $records = $query->fetchAll(); + $this->assertIsArray($records, + "We should have been able to select from the record from the db table."); + $this->assertCount(1, $records, + "There should only be a single db with this name"); + } +} diff --git a/tripal_chado/tests/src/Traits/ChadoStorageTestTrait.php b/tripal_chado/tests/src/Traits/ChadoStorageTestTrait.php index cd8c11653..7c3ddd999 100644 --- a/tripal_chado/tests/src/Traits/ChadoStorageTestTrait.php +++ b/tripal_chado/tests/src/Traits/ChadoStorageTestTrait.php @@ -757,10 +757,26 @@ public function setFieldsFromYaml($yaml_file, $top_level_key) { throw new \Exception("Unable to parse YAML file $yaml_file in order to set the fields for testing chadostorage."); } - if (!array_key_exists($top_level_key, $yaml_data)) { - throw new \Exception("The Top level key $top_level_key that you provided does not exist in the parsed YAML file: $yaml_file."); + // Check if we have a single top level key or if there are more levels. + $levels = explode('.', $top_level_key); + $data2return = $yaml_data; + $deepest_level = max(array_keys($levels)); + foreach($levels as $i => $key) { + if (!array_key_exists($key, $data2return)) { + throw new \Exception("The key $key (part of $top_level_key) that you provided does not exist in the parsed YAML file: $yaml_file."); + } + + + if ($i === $deepest_level AND $i !== 0) { + // If this is the deepest level and not the only level then we want to + // do something different to ensure we keep the structure of the fields array. + $data2return = [ $key => $data2return[$key] ]; + } + else { + $data2return = $data2return[$key]; + } } - $this->fields = $yaml_data[$top_level_key]; + $this->fields = $data2return; } } From dcb5224212ede702c4dbcf31bf489228536213b1 Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Tue, 24 Oct 2023 12:36:23 -0600 Subject: [PATCH 41/74] Ensure there is an error if the store_id is not used on the base_table of the field. --- .../src/Plugin/TripalStorage/ChadoStorage.php | 9 +++ .../ChadoStorageActions_StoreIdTest.php | 63 ++++++++++++++++--- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index 9a72f1ba5..26c10d689 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -1032,6 +1032,15 @@ protected function buildChadoRecords_store_id(array &$records, int $delta, array if (array_key_exists('chado_table', $storage_settings)) { $chado_table = $storage_settings['chado_table']; } + + // The store_id action should only be used for the base table... + if ($chado_table !== $context['base_table']) { + $this->logger->error($this->t('The @field.@key property type uses the ' + . 'store_id action type but is not assocatiated with the base table of the field. ' + . 'Either change the base_table of this field or use store_pkey instead.', + ['@field' => $context['field_name'], '@key' => $context['property_key']])); + } + // Now determine the primary key for the chado table. $chado_table_def = $this->connection->schema()->getTableDef($chado_table, ['format' => 'drupal']); $chado_table_pkey = $chado_table_def['primary key']; diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php index da8953c88..abe2a20c3 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php @@ -40,30 +40,33 @@ protected function setUp() :void { // We need to mock the logger to test the progress reporting. $container = \Drupal::getContainer(); $mock_logger = $this->getMockBuilder(\Drupal\tripal\Services\TripalLogger::class) - ->onlyMethods(['warning']) + ->onlyMethods(['warning', 'error']) ->getMock(); $mock_logger->method('warning') ->willReturnCallback(function($message, $context, $options) { print str_replace(array_keys($context), $context, $message); return NULL; }); + $mock_logger->method('error') + ->willReturnCallback(function($message, $context, $options) { + print str_replace(array_keys($context), $context, $message); + return NULL; + }); $container->set('tripal.logger', $mock_logger); $this->setUpChadoStorageTestEnviro(); } /** - * Test the read_value action. + * Test the store_id action. * - * Chado Table: project - * Columns: project_id*, name*, description + * Chado Table: db + * Columns: db_id*, name* * - * Specifically, - * - Ensure that a property with the read_value action has the value set - * - Ensure that a property with the read_value action can't change the value - * - That two fields accessing the same chado column do not conflict - * A. both read_value action for the same column - * B. one read_value and one store for the same column + * Specifically, ensure that a property with the store_id action + * - and a NULL value can insert a new record + * - has the value set on load + * - does not get changed on update */ public function testStoreIdAction() { @@ -155,4 +158,44 @@ public function testStoreIdAction() { $this->assertCount(1, $records, "There should only be a single db with this name"); } + + /** + * Test the store_id action. + * + * Chado Table: db + * Columns: db_id*, name* + * + * Specifically, ensure that a property with the store_id action + * MUST BE associated with the base table of the field + * BUT NEED NOT BE a typical base table. + */ + public function testStoreIdActionNotBase() { + + $field_name = 'test_non_base_match'; + + // Set the fields for this test and then re-populate the storage arrays. + $this->setFieldsFromYaml($this->yaml_file, "store_id.$field_name"); + $this->cleanChadoStorageValues(); + + // Test Case: Insert valid values when they do not yet exist in Chado. + // --------------------------------------------------------- + $insert_values = [ + $field_name => [ + [ + 'random_name' => NULL, + 'name' => 'Something random that is only here because this field is required.', + ], + ], + ]; + ob_start(); + $this->chadoStorageTestInsertValues($insert_values); + $printed_output = ob_get_clean(); + + $this->assertStringContainsString( + 'uses the store_id action type but is not assocatiated with the base table of the field', + $printed_output, + 'We did not get the error message we expected when using the store_id action for a non-base table.' + ); + + } } From 1e516717e0e07e6dfb86435a6949ed35f8f8053b Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Tue, 24 Oct 2023 13:07:59 -0600 Subject: [PATCH 42/74] Ensure that store_id properties do not try to use a table alias. --- .../src/Plugin/TripalStorage/ChadoStorage.php | 10 +++++-- .../ChadoStorageActions-FieldDefinitions.yml | 6 ---- .../ChadoStorageActions_StoreIdTest.php | 29 +++++++++++++++++++ 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index 26c10d689..d83afc9de 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -1045,12 +1045,16 @@ protected function buildChadoRecords_store_id(array &$records, int $delta, array $chado_table_def = $this->connection->schema()->getTableDef($chado_table, ['format' => 'drupal']); $chado_table_pkey = $chado_table_def['primary key']; - // Check if there is a table alias set and if so, then use it. + // For store_id action properties, the alias should always match the table name. $table_alias = $chado_table; + $this->setChadoTableAliasMapping($chado_table, $table_alias, $context['field_name'], $context['property_key']); + // If another alias is provided then we need to trow an exception. if (array_key_exists('chado_table_alias', $storage_settings)) { - $table_alias = $storage_settings['chado_table_alias']; + throw new \Exception($this->t('The @field.@key property type uses the ' + . 'store_id action type and tries to set a table alias, which are not ' + . 'supported for this type of action.', + ['@field' => $context['field_name'], '@key' => $context['property_key']])); } - $this->setChadoTableAliasMapping($chado_table, $table_alias, $context['field_name'], $context['property_key']); // Get the value if it is set. $record_id = $prop_value->getValue(); diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml index 876637084..488b71f0f 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml @@ -113,12 +113,6 @@ store_id: chado_table: 'db' chado_table_alias: 'fred' chado_column: 'db_id' - name: - propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' - action: 'store' - chado_table: 'db' - chado_table_alias: 'fred' - chado_column: 'name' store_pkey: diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php index abe2a20c3..caba6e5f4 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php @@ -196,6 +196,35 @@ public function testStoreIdActionNotBase() { $printed_output, 'We did not get the error message we expected when using the store_id action for a non-base table.' ); + } + /** + * Test the store_id action. + * + * Chado Table: db + * Columns: db_id*, name* + * + * Specifically, ensure that a property with the store_id action + * DOES NOT try to set a table alias. + */ + public function testStoreIdActionTableAlias() { + + $field_name = 'test_chado_alias'; + + // Set the fields for this test and then re-populate the storage arrays. + $this->setFieldsFromYaml($this->yaml_file, "store_id.$field_name"); + $this->cleanChadoStorageValues(); + + // Test Case: Insert valid values when they do not yet exist in Chado. + // --------------------------------------------------------- + $insert_values = [ + $field_name => [ + [ + 'random_name' => NULL, + ], + ], + ]; + $this->expectExceptionMessage('tries to set a table alias, which are not supported'); + $this->chadoStorageTestInsertValues($insert_values); } } From 4417156d9b3fef7dac4740cda6d71f3d6f0193aa Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Tue, 24 Oct 2023 13:38:28 -0600 Subject: [PATCH 43/74] Switch key of yaml to the method name. --- .../ChadoStorageActions-FieldDefinitions.yml | 18 +++++++----------- .../ChadoStorageActions_ReadValueTest.php | 2 +- .../ChadoStorageActions_StoreIdTest.php | 6 +++--- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml index 488b71f0f..5045b133f 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml @@ -3,7 +3,7 @@ ## ChadoStorageActionsTest.php ## ## The format is as follows: -## [action to be tested]: +## [test method which will be using the fields]: ## [field name]: ## field_name: [field name] ## base_table: [base table] @@ -17,7 +17,7 @@ ## Focus: Showing that the read_value action can read a value without any ## conflict with other fields. ## Chado Table: Project -read_value: +testReadValueAction: # The core field used to test the read action. test_read: field_name: 'test_read' @@ -72,7 +72,7 @@ read_value: ## base tables... rather it should work if: ## the chado table for the property = the base_table for the field. ## Chado Table: db -store_id: +testStoreIdAction: test_store_id: field_name: 'test_store_id' base_table: 'db' @@ -87,7 +87,8 @@ store_id: action: 'store' chado_table: 'db' chado_column: 'name' - # This field should not work as the store_id is not associated with the base table of the field. +# This field should not work as the store_id is not associated with the base table of the field. +testStoreIdActionNotBase: test_non_base_match: field_name: test_store_id base_table: cv @@ -102,7 +103,8 @@ store_id: action: 'store' chado_table: 'db' chado_column: 'name' - # Check that the chado table alias setting works on this action. +# Check that the chado table alias setting works on this action. +testStoreIdActionTableAlias: test_chado_alias: field_name: 'test_chado_alias' base_table: 'db' @@ -113,9 +115,3 @@ store_id: chado_table: 'db' chado_table_alias: 'fred' chado_column: 'db_id' - -store_pkey: - -store_link: - -store: diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php index 115f343a6..2c215edd9 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php @@ -68,7 +68,7 @@ protected function setUp() :void { public function testReadValueAction() { // Set the fields for this test and then re-populate the storage arrays. - $this->setFieldsFromYaml($this->yaml_file, 'read_value'); + $this->setFieldsFromYaml($this->yaml_file, 'testReadValueAction'); $this->cleanChadoStorageValues(); // Test Case: Insert valid values when they do not yet exist in Chado. diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php index caba6e5f4..7422b0a5d 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreIdTest.php @@ -73,7 +73,7 @@ public function testStoreIdAction() { $field_name = 'test_store_id'; // Set the fields for this test and then re-populate the storage arrays. - $this->setFieldsFromYaml($this->yaml_file, "store_id.$field_name"); + $this->setFieldsFromYaml($this->yaml_file, "testStoreIdAction"); $this->cleanChadoStorageValues(); // Test Case: Insert valid values when they do not yet exist in Chado. @@ -174,7 +174,7 @@ public function testStoreIdActionNotBase() { $field_name = 'test_non_base_match'; // Set the fields for this test and then re-populate the storage arrays. - $this->setFieldsFromYaml($this->yaml_file, "store_id.$field_name"); + $this->setFieldsFromYaml($this->yaml_file, "testStoreIdActionNotBase"); $this->cleanChadoStorageValues(); // Test Case: Insert valid values when they do not yet exist in Chado. @@ -212,7 +212,7 @@ public function testStoreIdActionTableAlias() { $field_name = 'test_chado_alias'; // Set the fields for this test and then re-populate the storage arrays. - $this->setFieldsFromYaml($this->yaml_file, "store_id.$field_name"); + $this->setFieldsFromYaml($this->yaml_file, "testStoreIdActionTableAlias"); $this->cleanChadoStorageValues(); // Test Case: Insert valid values when they do not yet exist in Chado. From aaf6ac5433617f4ca54ca16bb404675f0d043e65 Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Tue, 24 Oct 2023 15:55:52 -0600 Subject: [PATCH 44/74] Test read_value with an alias. --- .../ChadoStorageActions-FieldDefinitions.yml | 32 ++++++++++ .../ChadoStorageActions_ReadValueTest.php | 62 +++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml index 5045b133f..d81f5bf90 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml @@ -66,6 +66,38 @@ testReadValueAction: action: 'read_value' chado_table: 'project' chado_column: 'name' +# Ensure the read_value action works with an alias. +testReadValueActionTableAlias: + test_alias: + field_name: 'test_read' + base_table: 'feature' + properties: + record_id: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_pkey' + chado_table: 'project' + chado_table_alias: 'project_alias' + chado_column: 'project_id' + name_read: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'read_value' + chado_table: 'project' + chado_table_alias: 'project_alias' + chado_column: 'name' + test_noalias: + field_name: 'test_read' + base_table: 'feature' + properties: + record_id: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_pkey' + chado_table: 'project' + chado_column: 'project_id' + name_read: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'read_value' + chado_table: 'project' + chado_column: 'name' ## Focus: Ensure that we can create records by setting this to NULL. Also ensure ## that there are no assumptions that this only be used on our typical set of diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php index 2c215edd9..7d5da49ce 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php @@ -205,4 +205,66 @@ public function testReadValueAction() { $this->assertEquals($expected_name, $retrieved_name, "The name was not updated to match the other_field_store:name_store property."); } + + + /** + * Test the read_value action works with table alias. + * + * Chado Table: project + * Columns: project_id*, name*, description + * + * Specifically, ensure that a property with the read_value action + * - Can be used with a table alias. This is testing load only. + */ + public function testReadValueActionTableAlias() { + + // Set the fields for this test and then re-populate the storage arrays. + $this->setFieldsFromYaml($this->yaml_file, 'testReadValueActionTableAlias'); + $this->cleanChadoStorageValues(); + + // Create to project records for testing the load with later. + // Test Case: Insert valid values when they do not yet exist in Chado. + $test_values = [ + 'test_alias' => [ + 'name' => 'Project name for the aliased record', + ], + 'test_noalias' => [ + 'name' => 'Base Project Name', + ], + ]; + foreach ($test_values as $field => $values) { + $project_id = $this->chado_connection->insert('1:project') + ->fields($values) + ->execute(); + $this->assertIsNumeric($project_id, + "We should have been able to insert test data for $field into the project table with the values: " . print_r($values, TRUE)); + $test_values[$field]['project_id'] = $project_id; + } + + // For loading only the store id/pkey/link items should be populated. + $load_values = [ + 'test_alias' => [ + [ + 'record_id' => $test_values['test_alias']['project_id'], + ], + ], + 'test_noalias' => [ + [ + 'record_id' => $test_values['test_noalias']['project_id'], + ], + ], + ]; + $retrieved_values = $this->chadoStorageTestLoadValues($load_values); + + // Check that the name in our fields have been loaded. + foreach ($test_values as $field => $values) { + $ret_name = $retrieved_values[$field][0]['name_read']['value']->getValue(); + $this->assertEquals($test_values[$field]['name'], $ret_name, + "The name retrieved should match the one we inserted into chado for $field."); + + $ret_id = $retrieved_values[$field][0]['record_id']['value']->getValue(); + $this->assertEquals($test_values[$field]['project_id'], $ret_id, + "The project_id retrieved should match the one we inserted into chado for $field."); + } + } } From d7ebb51c0151889586e47e5c4d2e6dcf42ec5fde Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Tue, 24 Oct 2023 16:32:15 -0600 Subject: [PATCH 45/74] Start a join test. --- .../ChadoStorageActions-FieldDefinitions.yml | 21 ++++- .../ChadoStorageActions_ReadValueTest.php | 78 ++++++++++++++++++- 2 files changed, 96 insertions(+), 3 deletions(-) diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml index d81f5bf90..037dc8f2f 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml @@ -69,7 +69,7 @@ testReadValueAction: # Ensure the read_value action works with an alias. testReadValueActionTableAlias: test_alias: - field_name: 'test_read' + field_name: 'test_alias' base_table: 'feature' properties: record_id: @@ -85,7 +85,7 @@ testReadValueActionTableAlias: chado_table_alias: 'project_alias' chado_column: 'name' test_noalias: - field_name: 'test_read' + field_name: 'test_noalias' base_table: 'feature' properties: record_id: @@ -98,6 +98,23 @@ testReadValueActionTableAlias: action: 'read_value' chado_table: 'project' chado_column: 'name' +# Ensure we can read the value when a path is supplied (e.g. think old join action) +testReadValueActionJoin: + test_join: + field_name: 'test_join' + base_table: 'stock' + properties: + record_id: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_id' + chado_table: 'stock' + chado_column: 'stock_id' + cvterm_read: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'read_value' + chado_table: 'cvterm' + chado_column: 'name' + path: 'stock.stock_id=stock_cvterm.stock_id>stock_cvterm.cvterm_id=cvterm.cvterm_id' ## Focus: Ensure that we can create records by setting this to NULL. Also ensure ## that there are no assumptions that this only be used on our typical set of diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php index 7d5da49ce..ab708be1a 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php @@ -214,7 +214,8 @@ public function testReadValueAction() { * Columns: project_id*, name*, description * * Specifically, ensure that a property with the read_value action - * - Can be used with a table alias. This is testing load only. + * - Can be used with a table alias. + * Focusing on load since this action type does not impact insert/update. */ public function testReadValueActionTableAlias() { @@ -267,4 +268,79 @@ public function testReadValueActionTableAlias() { "The project_id retrieved should match the one we inserted into chado for $field."); } } + + /** + * Test read_value through a join. + * + * Base Table: Stock + * Columns: stock_id + * Chado Table: cvterm + * Columns: name + * + * Specically, testing that we can read the cvterm name for a stock record + * through the stock > stock_cvterm > cvterm join path. + * + * Again focusing on load since this action type does not impact insert/update. + */ + public function testReadValueActionJoin() { + + // Set the fields for this test and then re-populate the storage arrays. + $this->setFieldsFromYaml($this->yaml_file, 'testReadValueActionJoin'); + $this->cleanChadoStorageValues(); + + // Create the organism record needed for the stock. + $organism_id = $this->chado_connection->insert('1:organism') + ->fields([ + 'genus' => 'Tripalus', + 'species' => 'databasica', + ]) + ->execute(); + $this->assertIsNumeric($organism_id, + 'We should have been able to insert a organism for use with testing.'); + // Create the stock base record. + $stock_id = $this->chado_connection->insert('1:stock') + ->fields([ + 'type_id' => $this->getCvtermId('rdfs', 'comment'), + 'organism_id' => $organism_id, + 'uniquename' => uniqid(), + ]) + ->execute(); + $this->assertIsNumeric($stock_id, + 'We should have been able to insert a stock for use with testing.'); + // Create the pub record needed for the stock_cvterm. + $pub_id = $this->chado_connection->insert('1:pub') + ->fields([ + 'uniquename' => uniqid(), + 'type_id' => $this->getCvtermId('TPUB', '0000172'), + ]) + ->execute(); + $this->assertIsNumeric($pub_id, + 'We should have been able to insert a pub for use with testing.'); + // Now create 3 connections to cvterms for testing purposes. + $test_values = [ + [ + 'stock_id' => $stock_id, + 'cvterm_id' => $this->getCvtermId('SO', '0001778'), + 'pub_id' => $pub_id, + ], + [ + 'stock_id' => $stock_id, + 'cvterm_id' => $this->getCvtermId('CO_010', '0000044'), + 'pub_id' => $pub_id, + ], + [ + 'stock_id' => $stock_id, + 'cvterm_id' => $this->getCvtermId('TAXRANK', '0000034'), + 'pub_id' => $pub_id, + ] + ]; + foreach ($test_values as $delta => $values) { + $pkey = $this->chado_connection->insert('1:stock_cvterm') + ->fields($values) + ->execute(); + $this->assertIsNumeric($pkey, + "We should have been able to insert test data for $delta into the stock_cvterm table with the values: " . print_r($values, TRUE)); + $test_values[$delta]['stock_cvterm_id'] = $pkey; + } + } } From 693bf664bf98687952f3cde869d19d9a0fcad1d4 Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 25 Oct 2023 14:28:26 -0600 Subject: [PATCH 46/74] Fix some bugs with read_value path (i.e. join) actions. --- .../src/Plugin/TripalStorage/ChadoStorage.php | 38 ++++++++++--------- .../ChadoStorageActions-FieldDefinitions.yml | 2 +- .../ChadoStorageActions_ReadValueTest.php | 34 ++++++++++++----- 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index d83afc9de..c79ec1553 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -444,7 +444,9 @@ public function selectChadoRecord(&$records, $base_tables, $chado_table_alias, $ // Select the fields in the chado table. $select = $this->connection->select('1:'.$chado_table, 'ct'); - $select->fields('ct', array_keys($record['fields'])); + if (array_key_exists('fields', $record)) { + $select->fields('ct', array_keys($record['fields'])); + } // Add in any joins. if (array_key_exists('joins', $record)) { @@ -739,10 +741,11 @@ protected function setPropValues(&$values, $records) { if (in_array($action, ['read_value', 'join'])) { if (array_key_exists('chado_table', $prop_storage_settings)) { $chado_table = $prop_storage_settings['chado_table']; + $chado_table_alias = $this->getTableAliasForChadoTable($field_name, $key, $chado_table); } // Otherwise this is a join + we need the base table. // We can use the path to look this up. - elseif (array_key_exists('path', $prop_storage_settings)) { + if (array_key_exists('path', $prop_storage_settings)) { // Examples of the path: // - phylotree.analysis_id>analysis.analysis_id'. // - feature.type_id>cvterm.cvterm_id;cvterm.dbxref_id>dbxref.dbxref_id;dbxref.db_id>db.db_id' @@ -753,8 +756,8 @@ protected function setPropValues(&$values, $records) { list($left_table, $left_col) = explode(".", $left); // The base table is the left table of the first part of the path. $chado_table = $left_table; + $chado_table_alias = $left_table; } - $chado_table_alias = $this->getTableAliasForChadoTable($field_name, $key, $chado_table); $chado_column = $prop_storage_settings['chado_column']; $as = array_key_exists('as', $prop_storage_settings) ? $prop_storage_settings['as'] : $chado_column; $value = $records[$chado_table_alias][$delta]['fields'][$as]; @@ -949,22 +952,23 @@ protected function buildChadoRecords($values, bool $is_store) { foreach ($records as $table_name => $deltas) { foreach ($deltas as $delta => $record) { // First for all the fields... - foreach ($record['fields'] as $chado_column => $val) { - if (is_array($val) and $val[0] == 'REPLACE_BASE_RECORD_ID') { - $core_table = $val[1]; + if (array_key_exists('fields', $record)) { + foreach ($record['fields'] as $chado_column => $val) { + if (is_array($val) and $val[0] == 'REPLACE_BASE_RECORD_ID') { + $core_table = $val[1]; - // If the core table is set in the base record ids array and the - // value is not 0 then we can set this chado field now! - if (array_key_exists($core_table, $this->base_record_ids) and $this->base_record_ids[$core_table] != 0) { - $records[$table_name][$delta]['fields'][$chado_column] = $this->base_record_ids[$core_table]; - } - // If the base record ID is 0 then this is an insert and we - // don't yet have the base record ID. So, leave in the message - // to replace the ID so we can do so later. - if (array_key_exists($base_table, $this->base_record_ids) and $this->base_record_ids[$base_table] != 0) { - $records[$table_name][$delta]['fields'][$chado_column] = $this->base_record_ids[$base_table]; + // If the core table is set in the base record ids array and the + // value is not 0 then we can set this chado field now! + if (array_key_exists($core_table, $this->base_record_ids) and $this->base_record_ids[$core_table] != 0) { + $records[$table_name][$delta]['fields'][$chado_column] = $this->base_record_ids[$core_table]; + } + // If the base record ID is 0 then this is an insert and we + // don't yet have the base record ID. So, leave in the message + // to replace the ID so we can do so later. + if (array_key_exists($base_table, $this->base_record_ids) and $this->base_record_ids[$base_table] != 0) { + $records[$table_name][$delta]['fields'][$chado_column] = $this->base_record_ids[$base_table]; + } } - } } if (!array_key_exists('conditions', $record)) print_r($record); diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml index 037dc8f2f..ec8866858 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml @@ -114,7 +114,7 @@ testReadValueActionJoin: action: 'read_value' chado_table: 'cvterm' chado_column: 'name' - path: 'stock.stock_id=stock_cvterm.stock_id>stock_cvterm.cvterm_id=cvterm.cvterm_id' + path: 'stock.stock_id>stock_cvterm.stock_id;stock_cvterm.cvterm_id>cvterm.cvterm_id' ## Focus: Ensure that we can create records by setting this to NULL. Also ensure ## that there are no assumptions that this only be used on our typical set of diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php index ab708be1a..660a773ad 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php @@ -323,16 +323,6 @@ public function testReadValueActionJoin() { 'cvterm_id' => $this->getCvtermId('SO', '0001778'), 'pub_id' => $pub_id, ], - [ - 'stock_id' => $stock_id, - 'cvterm_id' => $this->getCvtermId('CO_010', '0000044'), - 'pub_id' => $pub_id, - ], - [ - 'stock_id' => $stock_id, - 'cvterm_id' => $this->getCvtermId('TAXRANK', '0000034'), - 'pub_id' => $pub_id, - ] ]; foreach ($test_values as $delta => $values) { $pkey = $this->chado_connection->insert('1:stock_cvterm') @@ -342,5 +332,29 @@ public function testReadValueActionJoin() { "We should have been able to insert test data for $delta into the stock_cvterm table with the values: " . print_r($values, TRUE)); $test_values[$delta]['stock_cvterm_id'] = $pkey; } + + // For loading only the store id/pkey/link items should be populated. + $load_values = [ + 'test_join' => [ + [ + 'record_id' => $test_values[0]['stock_id'], + ], + ], + ]; + $retrieved_values = $this->chadoStorageTestLoadValues($load_values); + + // Check that the name in our fields have been loaded. + $expected = [ + 'germline_variant', + ]; + foreach ($test_values as $delta => $values) { + $ret_term = $retrieved_values['test_join'][$delta]['cvterm_read']['value']->getValue(); + $this->assertEquals($expected[$delta], $ret_term, + "The cvterm name retrieved should match the one we inserted into chado for $delta."); + + $ret_id = $retrieved_values['test_join'][$delta]['record_id']['value']->getValue(); + $this->assertEquals($test_values[$delta]['stock_id'], $ret_id, + "The stock_id retrieved should match the one we inserted into chado for $delta."); + } } } From c16fd11fcddc409857fe85483c20f7b0fc80ba6e Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 25 Oct 2023 14:45:13 -0600 Subject: [PATCH 47/74] Ensure we hit the case where there are mutliple read_value fields for the same table. --- .../ChadoStorageActions-FieldDefinitions.yml | 21 ++++++++ .../ChadoStorageActions_ReadValueTest.php | 52 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml index ec8866858..1b5da92ea 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml @@ -115,6 +115,27 @@ testReadValueActionJoin: chado_table: 'cvterm' chado_column: 'name' path: 'stock.stock_id>stock_cvterm.stock_id;stock_cvterm.cvterm_id>cvterm.cvterm_id' +# Ensure read_value works when there isn't a store action for the same column. +testReadValueActionNoStore: + test_read: + field_name: 'test_read' + base_table: 'project' + properties: + record_id: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_id' + chado_table: 'project' + chado_column: 'project_id' + name_read: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'read_value' + chado_table: 'project' + chado_column: 'name' + description_read: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'read_value' + chado_table: 'project' + chado_column: 'description' ## Focus: Ensure that we can create records by setting this to NULL. Also ensure ## that there are no assumptions that this only be used on our typical set of diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php index 660a773ad..eb145a8cc 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php @@ -357,4 +357,56 @@ public function testReadValueActionJoin() { "The stock_id retrieved should match the one we inserted into chado for $delta."); } } + + /** + * Test read_value works when there is no store on the same column. + * + * Chado Table: project + * Columns: project_id*, name*, description + * + * Specifically testing that we can read the project name for an existing + * project record when there is no store property for the project name. + * + * Again focusing on load since this action type does not impact insert/update. + */ + public function testReadValueActionNoStore() { + + // Set the fields for this test and then re-populate the storage arrays. + $this->setFieldsFromYaml($this->yaml_file, 'testReadValueActionNoStore'); + $this->cleanChadoStorageValues(); + + $project_name = uniqid(); + $project_description = 'This is a random comment with a unique ending ' . uniqid(); + $project_id = $this->chado_connection->insert('1:project') + ->fields([ + 'name' => $project_name, + 'description' => $project_description, + ]) + ->execute(); + $this->assertIsNumeric($project_id, + 'We should have been able to insert a project for use with testing.'); + + // For loading only the store id/pkey/link items should be populated. + $load_values = [ + 'test_read' => [ + [ + 'record_id' => $project_id, + ], + ], + ]; + $retrieved_values = $this->chadoStorageTestLoadValues($load_values); + + // Check that the name in our fields have been loaded. + $ret_name = $retrieved_values['test_read'][0]['name_read']['value']->getValue(); + $this->assertEquals($project_name, $ret_name, + "The name retrieved should match the one we inserted into chado."); + + $ret_descrip = $retrieved_values['test_read'][0]['description_read']['value']->getValue(); + $this->assertEquals($project_description, $ret_descrip, + "The description retrieved should match the one we inserted into chado."); + + $ret_id = $retrieved_values['test_read'][0]['record_id']['value']->getValue(); + $this->assertEquals($project_id, $ret_id, + "The project_id retrieved should match the one we inserted into chado."); + } } From 131547505342ef3090aab4fa127a8e26386cdd8f Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 25 Oct 2023 14:53:55 -0600 Subject: [PATCH 48/74] Change groups of other chado storage tests for consistency. --- .../Kernel/Plugin/ChadoStorage/ChadoAnalysisDefaultTest.php | 3 +-- .../src/Kernel/Plugin/ChadoStorage/ChadoContactDefaultTest.php | 3 +-- .../Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php | 1 + .../src/Kernel/Plugin/ChadoStorage/ChadoLinkerTableTest.php | 1 + 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoAnalysisDefaultTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoAnalysisDefaultTest.php index 43770cccf..5c266e4e3 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoAnalysisDefaultTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoAnalysisDefaultTest.php @@ -37,9 +37,8 @@ * * @group Tripal * @group Tripal Chado - * @group Tripal Chado Fields - * @group Tripal Chado Fields Analysis * @group ChadoStorage + * @group ChadoStorage Fields */ class ChadoAnalysisDefaultTest extends ChadoTestKernelBase { diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoContactDefaultTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoContactDefaultTest.php index bb44b1529..5969b702d 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoContactDefaultTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoContactDefaultTest.php @@ -30,9 +30,8 @@ * * @group Tripal * @group Tripal Chado - * @group Tripal Chado Fields - * @group Tripal Chado Fields Contact * @group ChadoStorage + * @group ChadoStorage Fields */ class ChadoContactDefaultTest extends ChadoTestKernelBase { diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php index 15719019c..71e501933 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerPropertyDefaultTest.php @@ -35,6 +35,7 @@ * @group Tripal * @group Tripal Chado * @group ChadoStorage + * @group ChadoStorage Fields */ class ChadoLinkerPropertyDefaultTest extends ChadoTestKernelBase { diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerTableTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerTableTest.php index cbaa0618f..f01b02be4 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerTableTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoLinkerTableTest.php @@ -38,6 +38,7 @@ * @group Tripal * @group Tripal Chado * @group ChadoStorage + * @group ChadoStorage Fields */ class ChadoLinkerTableTest extends ChadoTestKernelBase { From dc930742ed5cf585518bc602f8d9310b548f448d Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 25 Oct 2023 16:16:14 -0600 Subject: [PATCH 49/74] Add store_pkey action tests. --- .../ChadoStorageActions-FieldDefinitions.yml | 36 ++++ .../ChadoStorageActions_StorePkeyTest.php | 181 ++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StorePkeyTest.php diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml index 1b5da92ea..51e464d16 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml @@ -185,3 +185,39 @@ testStoreIdActionTableAlias: chado_table: 'db' chado_table_alias: 'fred' chado_column: 'db_id' + +## Focus: Ensure that we can create records by setting this to NULL. +## Chado Table: cvterm +testStorePKeyAction: + test_field: + field_name: 'test_store_id' + base_table: 'cv' + properties: + primary_key: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_pkey' + chado_table: 'db' + chado_column: 'db_id' + name: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'store' + chado_table: 'db' + chado_column: 'name' +# Check that the chado table alias setting works on this action. +testStorePKeyActionTableAlias: + test_chado_alias: + field_name: 'test_chado_alias' + base_table: 'db' + properties: + primary_key: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_pkey' + chado_table: 'db' + chado_table_alias: 'fred' + chado_column: 'db_id' + name: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'store' + chado_table: 'db' + chado_table_alias: 'fred' + chado_column: 'name' diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StorePkeyTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StorePkeyTest.php new file mode 100644 index 000000000..6f765cf79 --- /dev/null +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StorePkeyTest.php @@ -0,0 +1,181 @@ +set('is_a_test_environment', TRUE); + + // We need to mock the logger to test the progress reporting. + $container = \Drupal::getContainer(); + $mock_logger = $this->getMockBuilder(\Drupal\tripal\Services\TripalLogger::class) + ->onlyMethods(['warning', 'error']) + ->getMock(); + $mock_logger->method('warning') + ->willReturnCallback(function($message, $context, $options) { + print str_replace(array_keys($context), $context, $message); + return NULL; + }); + $mock_logger->method('error') + ->willReturnCallback(function($message, $context, $options) { + print str_replace(array_keys($context), $context, $message); + return NULL; + }); + $container->set('tripal.logger', $mock_logger); + + $this->setUpChadoStorageTestEnviro(); + } + + /** + * DATA PROVIDER: Provide field names. + * + * We essentially want to run the exact same test both when an alias is + * supplied and when it's not. Thus we are using a data provider to do that + * without duplicating code. + */ + public function provideFieldNames() { + return [ + [ + 'testStorePKeyAction', + 'test_field' + ], + [ + 'testStorePKeyActionTableAlias', + 'test_chado_alias' + ] + ]; + } + + /** + * Test the store_pkey action. + * + * @dataProvider provideFieldNames + * + * Chado Table: db + * Columns: db_id*, name* + * + * Specifically, ensure that a property with the store_pkey action + * - and a NULL value can insert a new record + * - has the value set on load + * - does not get changed on update + */ + public function testStorePKeyAction($top_level_key, $field_name) { + + // Set the fields for this test and then re-populate the storage arrays. + $this->setFieldsFromYaml($this->yaml_file, $top_level_key); + $this->cleanChadoStorageValues(); + + // Test Case: Insert valid values when they do not yet exist in Chado. + // --------------------------------------------------------- + $insert_values = [ + $field_name => [ + [ + 'primary_key' => NULL, + 'name' => 'Something random that is only here because this field is required.', + ], + ], + ]; + $this->chadoStorageTestInsertValues($insert_values); + + // Check that there is now a single db record. + $query = $this->chado_connection->select('1:db', 'db') + ->fields('db', ['db_id', 'name']) + ->condition('db.name', $insert_values[$field_name][0]['name'], '=') + ->execute(); + $records = $query->fetchAll(); + $this->assertIsArray($records, + "We should have been able to select from the record from the db table."); + $this->assertCount(1, $records, + "There should only be a single db with this name"); + + $db_id = $records[0]->db_id; + + // Test Case: Load values existing in Chado. + // --------------------------------------------------------- + // First we want to reset all the chado storage arrays to ensure we are + // doing a clean test. The values will purposefully remain in Chado but the + // Property Types, Property Values and Data Values will be built from scratch. + $this->cleanChadoStorageValues(); + + // For loading only the store id/pkey/link items should be populated. + // Since the id is passed in we're just checking it was set to the value property. + $load_values = [ + $field_name => [ + [ + 'primary_key' => $db_id, + 'name' => NULL, + ], + ], + ]; + $retrieved_values = $this->chadoStorageTestLoadValues($load_values); + + // Check that the name in our fields have been loaded. + $retrieved_id = $retrieved_values[$field_name][0]['primary_key']['value']->getValue(); + $this->assertEquals($db_id, $retrieved_id, + "The ID we retrieved for the $field_name field did not match the one set with a store_pkey attribute during insert."); + + // We also check the name to be thorough. + $expected_name = $insert_values[$field_name][0]['name']; + $retrieved_name = $retrieved_values[$field_name][0]['name']['value']->getValue(); + $this->assertEquals($expected_name, $retrieved_name, + "The name we retrieved for the $field_name field did not match the one set with a store attribute during insert."); + + // Test Case: Update values in Chado using ChadoStorage. + // --------------------------------------------------------- + // When updating we need all the store id/pkey/link records + // and all values of the other properties. + $update_values = [ + $field_name => [ + [ + 'primary_key' => $db_id, + 'name' => 'Something random that is only here because this field is required.', + ], + ], + ]; + + // Let's test this without changing anything. + $this->chadoStorageTestUpdateValues($update_values); + + // Check that there is still only a single db record with this name. + $query = $this->chado_connection->select('1:db', 'db') + ->fields('db', ['db_id', 'name']) + ->condition('db.name', $update_values[$field_name][0]['name'], '=') + ->execute(); + $records = $query->fetchAll(); + $this->assertIsArray($records, + "We should have been able to select from the record from the db table."); + $this->assertCount(1, $records, + "There should only be a single db with this name"); + } +} From 1fc29382d1ce90d71335d00246d0ffade2b8cfd8 Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 25 Oct 2023 16:56:52 -0600 Subject: [PATCH 50/74] Stub out tests for store and store_link. --- .../ChadoStorageActions-FieldDefinitions.yml | 8 ++ .../ChadoStorageActions_StoreLinkTest.php | 80 +++++++++++++++++++ .../ChadoStorageActions_StoreTest.php | 80 +++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreLinkTest.php create mode 100644 tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreTest.php diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml index 51e464d16..6e8e261e7 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml @@ -221,3 +221,11 @@ testStorePKeyActionTableAlias: chado_table: 'db' chado_table_alias: 'fred' chado_column: 'name' + +## Focus: +## Chado Table: +testStoreAction: + +## Focus: +## Chado Table: +testStoreLinkAction: diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreLinkTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreLinkTest.php new file mode 100644 index 000000000..933d5ce0a --- /dev/null +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreLinkTest.php @@ -0,0 +1,80 @@ +set('is_a_test_environment', TRUE); + + // We need to mock the logger to test the progress reporting. + $container = \Drupal::getContainer(); + $mock_logger = $this->getMockBuilder(\Drupal\tripal\Services\TripalLogger::class) + ->onlyMethods(['warning', 'error']) + ->getMock(); + $mock_logger->method('warning') + ->willReturnCallback(function($message, $context, $options) { + print str_replace(array_keys($context), $context, $message); + return NULL; + }); + $mock_logger->method('error') + ->willReturnCallback(function($message, $context, $options) { + print str_replace(array_keys($context), $context, $message); + return NULL; + }); + $container->set('tripal.logger', $mock_logger); + + $this->setUpChadoStorageTestEnviro(); + } + +/** + * Test the store_link action. + * + * Chado Table: + * Columns: + * + * Specifically, ensure that a property with the store action + * - + */ + public function testStoreLinkAction() { + + // Set the fields for this test and then re-populate the storage arrays. + // $this->setFieldsFromYaml($this->yaml_file, 'testStoreLinkAction'); + // $this->cleanChadoStorageValues(); + + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +} diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreTest.php new file mode 100644 index 000000000..87acccfe8 --- /dev/null +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreTest.php @@ -0,0 +1,80 @@ +set('is_a_test_environment', TRUE); + + // We need to mock the logger to test the progress reporting. + $container = \Drupal::getContainer(); + $mock_logger = $this->getMockBuilder(\Drupal\tripal\Services\TripalLogger::class) + ->onlyMethods(['warning', 'error']) + ->getMock(); + $mock_logger->method('warning') + ->willReturnCallback(function($message, $context, $options) { + print str_replace(array_keys($context), $context, $message); + return NULL; + }); + $mock_logger->method('error') + ->willReturnCallback(function($message, $context, $options) { + print str_replace(array_keys($context), $context, $message); + return NULL; + }); + $container->set('tripal.logger', $mock_logger); + + $this->setUpChadoStorageTestEnviro(); + } + +/** + * Test the store action. + * + * Chado Table: + * Columns: + * + * Specifically, ensure that a property with the store action + * - + */ + public function testStoreAction() { + + // Set the fields for this test and then re-populate the storage arrays. + // $this->setFieldsFromYaml($this->yaml_file, 'testStoreAction'); + // $this->cleanChadoStorageValues(); + + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +} From eb4d78ba646a72050934369910a72161fcde98b2 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Thu, 26 Oct 2023 12:15:23 -0600 Subject: [PATCH 51/74] Store test for alias. --- .../ChadoStorageActions-FieldDefinitions.yml | 65 ++++- .../ChadoStorageActions_StoreTest.php | 224 +++++++++++++++++- 2 files changed, 282 insertions(+), 7 deletions(-) diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml index 6e8e261e7..f5b208813 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml @@ -222,9 +222,68 @@ testStorePKeyActionTableAlias: chado_table_alias: 'fred' chado_column: 'name' -## Focus: -## Chado Table: -testStoreAction: +## Focus: Ensure that a property with the store action +## - can be inserted when an alias is used on a non-base table +## - can be loaded when an alias is used on a non-base table +## - can be updated when an alias is used on a non-base table +## Chado Table: featureprop +testStoreActionAlias: + test_store_alias: + field_name: 'test_store_alias' + base_table: 'feature' + properties: + primary_key: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_pkey' + chado_table: 'featureprop' + chado_table_alias: 'pippin' + chado_column: 'featureprop_id' + fkey: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'featureprop' + chado_table_alias: 'pippin' + chado_column: 'feature_id' + type: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'featureprop' + chado_table_alias: 'pippin' + chado_column: 'type_id' + rank: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'featureprop' + chado_table_alias: 'pippin' + chado_column: 'rank' + test_store_other_alias: + field_name: 'test_store_other_alias' + base_table: 'feature' + properties: + primary_key: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_pkey' + chado_table: 'featureprop' + chado_table_alias: 'merry' + chado_column: 'featureprop_id' + fkey: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'featureprop' + chado_table_alias: 'merry' + chado_column: 'feature_id' + type: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'featureprop' + chado_table_alias: 'merry' + chado_column: 'type_id' + rank: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'featureprop' + chado_table_alias: 'merry' + chado_column: 'rank' ## Focus: ## Chado Table: diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreTest.php index 87acccfe8..46fcc8612 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreTest.php @@ -13,6 +13,17 @@ /** * Tests that specific ChadoStorage actions perform as expected. * + * NOTE: The store action is actually tested fairly well as part of the testing + * for other actions. Specifically, pretty much every action test includes a store + * property and the value of that property is checked alongside the other properties + * as a way to confirm that the full record loaded properly. This was especially + * necessary for the store_* actions since they are set before loading so checking + * the store property is needed to ensure the record was actually loaded based + * on the pre-set keys. + * + * Anyway, as such, this class only focuses on testing edge cases like alias use + * and the delete_if_empty setting. + * * @group Tripal * @group Tripal Chado * @group ChadoStorage @@ -28,6 +39,8 @@ class ChadoStorageActions_StoreTest extends ChadoTestKernelBase { protected $yaml_file = __DIR__ . "/ChadoStorageActions-FieldDefinitions.yml"; + protected int $feature_id; + /** * {@inheritdoc} */ @@ -55,18 +68,221 @@ protected function setUp() :void { $container->set('tripal.logger', $mock_logger); $this->setUpChadoStorageTestEnviro(); + + // Create the organism record needed for testing. + $organism_id = $this->chado_connection->insert('1:organism') + ->fields([ + 'genus' => 'Tripalus', + 'species' => 'databasica', + ]) + ->execute(); + $this->assertIsNumeric($organism_id, + 'We should have been able to insert a organism for use with testing.'); + // Create the feature record needed for testing. + $this->feature_id = $this->chado_connection->insert('1:feature') + ->fields([ + 'organism_id' => $organism_id, + 'type_id' => $this->getCvtermId('rdfs','type'), + 'uniquename' => uniqid(), + ]) + ->execute(); + $this->assertIsNumeric($this->feature_id, + 'We should have been able to insert a feature for use with testing.'); + } -/** - * Test the store action. + /** + * Test the store action when an alias is set and it's on a non-base table. + * + * Chado Table: + * Columns: + * + * Specifically, ensure that a property with the store action + * - can be inserted when an alias is used on a non-base table + * - can be loaded when an alias is used on a non-base table + * - can be updated when an alias is used on a non-base table + */ + public function testStoreActionAlias() { + + // Set the fields for this test and then re-populate the storage arrays. + $this->setFieldsFromYaml($this->yaml_file, 'testStoreActionAlias'); + $this->cleanChadoStorageValues(); + + $types_used = [ + 'test_store_alias' => $this->getCvtermId('schema', 'comment'), + 'test_store_other_alias' => $this->getCvtermId('schema', 'description'), + ]; + + // Test Case: Insert valid values when they do not yet exist in Chado. + // --------------------------------------------------------- + $insert_values = [ + 'test_store_alias' => [ + [ + 'primary_key' => NULL, + 'fkey' => $this->feature_id, + 'type' => $types_used['test_store_alias'], + 'rank' => 0 + ], + [ + 'primary_key' => NULL, + 'fkey' => $this->feature_id, + 'type' => $types_used['test_store_alias'], + 'rank' => 1 + ], + ], + 'test_store_other_alias' => [ + [ + 'primary_key' => NULL, + 'fkey' => $this->feature_id, + 'type' => $types_used['test_store_other_alias'], + 'rank' => 0 + ], + [ + 'primary_key' => NULL, + 'fkey' => $this->feature_id, + 'type' => $types_used['test_store_other_alias'], + 'rank' => 3 + ], + ], + ]; + $this->chadoStorageTestInsertValues($insert_values); + + $query = $this->chado_connection->select('1:featureprop', 'prop') + ->fields('prop', ['featureprop_id', 'feature_id', 'type_id', 'rank']) + ->execute(); + $inserted_records = $query->fetchAll(); + $this->assertIsArray($inserted_records, + "We should have been able to select from the records from the featureprop table."); + $this->assertCount(4, $inserted_records, + "We did not get the number of records in the featureprop table that we excepted after insert."); + + // Ensure there are to records for each field. + foreach (['test_store_alias', 'test_store_other_alias'] as $field_name) { + $query = $this->chado_connection->select('1:featureprop', 'prop') + ->fields('prop', ['featureprop_id']) + ->condition('prop.type_id', $types_used[$field_name], '=') + ->orderBy('rank') + ->execute(); + $varname = $field_name . '_pkeys'; + $$varname = $query->fetchCol(); + $this->assertIsArray($$varname, + "We should have been able to select from the records from the featureprop table."); + $this->assertCount(2, $$varname, + "We did not get the number of records in the featureprop table for $field_name that we excepted after insert."); + } + + // Test Case: Load values existing in Chado. + // --------------------------------------------------------- + // First we want to reset all the chado storage arrays to ensure we are + // doing a clean test. The values will purposefully remain in Chado but the + // Property Types, Property Values and Data Values will be built from scratch. + $this->cleanChadoStorageValues(); + + // For loading only the store id/pkey/link items should be populated. + $load_values = [ + 'test_store_alias' => [ + [ + 'primary_key' => $test_store_alias_pkeys[0], + ], + [ + 'primary_key' => $test_store_alias_pkeys[1], + ], + ], + 'test_store_other_alias' => [ + [ + 'primary_key' => $test_store_other_alias_pkeys[0], + ], + [ + 'primary_key' => $test_store_other_alias_pkeys[1], + ], + ], + ]; + $retrieved_values = $this->chadoStorageTestLoadValues($load_values); + + // Check that the store values in our fields have been loaded as they were inserted. + foreach ($insert_values as $field_name => $delta_records) { + foreach ($delta_records as $delta => $expected_values) { + foreach(['fkey', 'type', 'rank'] as $property) { + $retrieved = $retrieved_values[$field_name][$delta][$property]['value']->getValue(); + $expected = $expected_values[$property]; + $this->assertEquals($expected, $retrieved, + "The value we retrieved for $field_name.$delta.$property did not match the one set with a store attribute during insert."); + } + } + } + + + // Test Case: Update values in Chado using ChadoStorage. + // --------------------------------------------------------- + // When updating we need all the store id/pkey/link records + // and all values of the other properties. + $update_values = $insert_values; + $update_values['test_store_alias'][0]['primary_key'] = $test_store_alias_pkeys[0]; + $update_values['test_store_alias'][1]['primary_key'] = $test_store_alias_pkeys[1]; + $update_values['test_store_other_alias'][0]['primary_key'] = $test_store_other_alias_pkeys[0]; + $update_values['test_store_other_alias'][1]['primary_key'] = $test_store_other_alias_pkeys[1]; + + // Let's test this with a change. + $update_values['test_store_other_alias'][1]['rank'] = 1; + $this->chadoStorageTestUpdateValues($update_values); + + $query = $this->chado_connection->select('1:featureprop', 'prop') + ->fields('prop', ['featureprop_id', 'feature_id', 'type_id', 'rank']) + ->execute(); + $records = $query->fetchAll(); + $this->assertIsArray($records, + "We should have been able to select from the records from the featureprop table."); + $this->assertCount(4, $records, + "We did not get the number of records in the featureprop table that we excepted after update."); + + // Finally check that the change happened in the database. + /** This is not an easy check since ChadoStorage deletes all these records + * and recreates them... hense the primary keys are incremented and do not + * remain constant. + print_r($records); + $query = $this->chado_connection->select('1:featureprop', 'prop') + ->fields('prop', ['rank']) + ->condition('prop.featureprop_id', $test_store_other_alias_pkeys[1], '=') + ->execute(); + $ret_rank = $query->fetchField(); + $this->assertEquals(1, $ret_rank, + "The rank does not seem to have been updated as we expected."); + */ + + } + + /** + * Test the store action when an alias is set and it's on a base table. + * + * Chado Table: + * Columns: + * + * Specifically, ensure that a property with the store action + * - throws an error when an alias is set and the store is on a base_table. + */ + public function testStoreActionAliasBase() { + + // Set the fields for this test and then re-populate the storage arrays. + // $this->setFieldsFromYaml($this->yaml_file, 'testStoreAction'); + // $this->cleanChadoStorageValues(); + + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + + /** + * Test the store action delete_if_empty on insert and update. * * Chado Table: * Columns: * * Specifically, ensure that a property with the store action - * - + * - is deleted if it's an empty string and delete_if_empty is true + * - is kept and inserted as an empty string if delete_if_empty is false */ - public function testStoreAction() { + public function testStoreActionDeleteIfEmpty() { // Set the fields for this test and then re-populate the storage arrays. // $this->setFieldsFromYaml($this->yaml_file, 'testStoreAction'); From bcbf4cf75304b967f7dafa4c2a9e6873e8ce8b15 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Thu, 26 Oct 2023 14:14:01 -0600 Subject: [PATCH 52/74] Add delete_if_empty test for store action. --- .../ChadoStorageActions-FieldDefinitions.yml | 76 +++++++++ .../ChadoStorageActions_StoreTest.php | 152 ++++++++++++++---- 2 files changed, 196 insertions(+), 32 deletions(-) diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml index f5b208813..be7b9816e 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml @@ -285,6 +285,82 @@ testStoreActionAlias: chado_table_alias: 'merry' chado_column: 'rank' +## Focus: Ensure that a property with the store action +## - is deleted if it's an empty string and delete_if_empty is true +## - is kept and inserted as an empty string if delete_if_empty is false +## Chado Table: featureprop +testStoreActionDeleteIfEmpty: + test_store_alias: + field_name: 'test_store_alias' + base_table: 'feature' + properties: + primary_key: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_pkey' + chado_table: 'featureprop' + chado_table_alias: 'pippin' + chado_column: 'featureprop_id' + fkey: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'featureprop' + chado_table_alias: 'pippin' + chado_column: 'feature_id' + type: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'featureprop' + chado_table_alias: 'pippin' + chado_column: 'type_id' + value: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'store' + chado_table: 'featureprop' + chado_table_alias: 'pippin' + chado_column: 'value' + delete_if_empty: TRUE + rank: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'featureprop' + chado_table_alias: 'pippin' + chado_column: 'rank' + test_store_other_alias: + field_name: 'test_store_other_alias' + base_table: 'feature' + properties: + primary_key: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_pkey' + chado_table: 'featureprop' + chado_table_alias: 'merry' + chado_column: 'featureprop_id' + fkey: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'featureprop' + chado_table_alias: 'merry' + chado_column: 'feature_id' + type: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'featureprop' + chado_table_alias: 'merry' + chado_column: 'type_id' + value: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'store' + chado_table: 'featureprop' + chado_table_alias: 'merry' + chado_column: 'value' + delete_if_empty: FALSE + rank: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'featureprop' + chado_table_alias: 'merry' + chado_column: 'rank' + ## Focus: ## Chado Table: testStoreLinkAction: diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreTest.php index 46fcc8612..0ce8b7abd 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreTest.php @@ -94,8 +94,8 @@ protected function setUp() :void { /** * Test the store action when an alias is set and it's on a non-base table. * - * Chado Table: - * Columns: + * Chado Table: featureprop + * Columns: featureprop_id*, feature_id*, type_id*, value, rank* * * Specifically, ensure that a property with the store action * - can be inserted when an alias is used on a non-base table @@ -211,7 +211,6 @@ public function testStoreActionAlias() { } } - // Test Case: Update values in Chado using ChadoStorage. // --------------------------------------------------------- // When updating we need all the store id/pkey/link records @@ -251,32 +250,11 @@ public function testStoreActionAlias() { } - /** - * Test the store action when an alias is set and it's on a base table. - * - * Chado Table: - * Columns: - * - * Specifically, ensure that a property with the store action - * - throws an error when an alias is set and the store is on a base_table. - */ - public function testStoreActionAliasBase() { - - // Set the fields for this test and then re-populate the storage arrays. - // $this->setFieldsFromYaml($this->yaml_file, 'testStoreAction'); - // $this->cleanChadoStorageValues(); - - // Stop here and mark this test as incomplete. - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); - } - /** * Test the store action delete_if_empty on insert and update. * - * Chado Table: - * Columns: + * Chado Table: featureprop + * Columns: featureprop_id*, feature_id*, type_id*, value*, rank* * * Specifically, ensure that a property with the store action * - is deleted if it's an empty string and delete_if_empty is true @@ -285,12 +263,122 @@ public function testStoreActionAliasBase() { public function testStoreActionDeleteIfEmpty() { // Set the fields for this test and then re-populate the storage arrays. - // $this->setFieldsFromYaml($this->yaml_file, 'testStoreAction'); - // $this->cleanChadoStorageValues(); + $this->setFieldsFromYaml($this->yaml_file, 'testStoreActionDeleteIfEmpty'); + $this->cleanChadoStorageValues(); + + $types_used = [ + 'test_store_alias' => $this->getCvtermId('schema', 'comment'), + 'test_store_other_alias' => $this->getCvtermId('schema', 'description'), + ]; - // Stop here and mark this test as incomplete. - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); + // Test Case: Insert valid values when they do not yet exist in Chado. + // --------------------------------------------------------- + $insert_values = [ + 'test_store_alias' => [ + [ + 'primary_key' => NULL, + 'fkey' => $this->feature_id, + 'type' => $types_used['test_store_alias'], + 'value' => '', // Should NOT be inserted since delete_if_empty: TRUE + 'rank' => 0 + ], + [ + 'primary_key' => NULL, + 'fkey' => $this->feature_id, + 'type' => $types_used['test_store_alias'], + 'value' => 'pippin', + 'rank' => 1 + ], + [ + 'primary_key' => NULL, + 'fkey' => $this->feature_id, + 'type' => $types_used['test_store_alias'], + 'value' => 'samwise', + 'rank' => 2 + ], + ], + 'test_store_other_alias' => [ + [ + 'primary_key' => NULL, + 'fkey' => $this->feature_id, + 'type' => $types_used['test_store_other_alias'], + 'value' => 'merry', + 'rank' => 0 + ], + [ + 'primary_key' => NULL, + 'fkey' => $this->feature_id, + 'type' => $types_used['test_store_other_alias'], + 'value' => '', // SHOULD be inserted as delete_if_empty: FALSE + 'rank' => 3 + ], + ], + ]; + $this->chadoStorageTestInsertValues($insert_values); + + $query = $this->chado_connection->select('1:featureprop', 'prop') + ->fields('prop', ['featureprop_id', 'feature_id', 'type_id', 'rank']) + ->execute(); + $inserted_records = $query->fetchAll(); + $this->assertIsArray($inserted_records, + "We should have been able to select from the records from the featureprop table."); + $this->assertCount(4, $inserted_records, + "We did not get the number of records in the featureprop table that we excepted after insert."); + + // Ensure there are to records for each field. + foreach (['test_store_alias' => 2, 'test_store_other_alias' => 2] as $field_name => $expected_count) { + $query = $this->chado_connection->select('1:featureprop', 'prop') + ->fields('prop', ['featureprop_id']) + ->condition('prop.type_id', $types_used[$field_name], '=') + ->orderBy('rank') + ->execute(); + $varname = $field_name . '_pkeys'; + $$varname = $query->fetchCol(); + $this->assertIsArray($$varname, + "We should have been able to select from the records from the featureprop table."); + $this->assertCount($expected_count, $$varname, + "We did not get the number of records in the featureprop table for $field_name that we excepted after insert."); + } + + // Test Case: Update values in Chado using ChadoStorage. + // --------------------------------------------------------- + // When updating we need all the store id/pkey/link records + // and all values of the other properties. + $update_values = $insert_values; + $update_values['test_store_alias'][1]['primary_key'] = $test_store_alias_pkeys[0]; + $update_values['test_store_alias'][2]['primary_key'] = $test_store_alias_pkeys[1]; + $update_values['test_store_other_alias'][0]['primary_key'] = $test_store_other_alias_pkeys[0]; + $update_values['test_store_other_alias'][1]['primary_key'] = $test_store_other_alias_pkeys[1]; + + // Now this one should be removed too. + $update_values['test_store_alias'][2]['value'] = ''; + // Add another empty value which should be kept. + $update_values['test_store_other_alias'][2] = $insert_values['test_store_other_alias'][1]; + $update_values['test_store_other_alias'][2]['rank'] = 5; + $this->chadoStorageTestUpdateValues($update_values); + + $query = $this->chado_connection->select('1:featureprop', 'prop') + ->fields('prop', ['featureprop_id', 'feature_id', 'type_id', 'rank']) + ->execute(); + $records = $query->fetchAll(); + $this->assertIsArray($records, + "We should have been able to select from the records from the featureprop table."); + $this->assertCount(4, $records, + "We did not get the number of records in the featureprop table that we excepted after update."); + + // Ensure there are to records for each field. + foreach (['test_store_alias' => 1, 'test_store_other_alias' => 3] as $field_name => $expected_count) { + $query = $this->chado_connection->select('1:featureprop', 'prop') + ->fields('prop', ['featureprop_id']) + ->condition('prop.type_id', $types_used[$field_name], '=') + ->orderBy('rank') + ->execute(); + $varname = $field_name . '_pkeys'; + $$varname = $query->fetchCol(); + $this->assertIsArray($$varname, + "We should have been able to select from the records from the featureprop table."); + $this->assertCount($expected_count, $$varname, + "We did not get the number of records in the featureprop table for $field_name that we excepted after insert."); + } } } From 1013b8551b211c801585d56bf758a5a623a1560d Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Fri, 27 Oct 2023 15:09:55 -0600 Subject: [PATCH 53/74] Fix bug where condition did not have value set. --- tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index 3a466bff0..fcb2407ff 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -979,7 +979,7 @@ protected function buildChadoRecords($values, bool $is_store) { // If the core table is set in the base record ids array and the // value is not 0 then we can set this condition now! if (array_key_exists($core_table, $this->base_record_ids) and $this->base_record_ids[$core_table] != 0) { - $records[$table_name][$delta]['conditions'][$chado_column] = $this->base_record_ids[$core_table]; + $records[$table_name][$delta]['conditions'][$chado_column]['value'] = $this->base_record_ids[$core_table]; } // If the base record ID is 0 then this is an insert and we // don't yet have the base record ID. So, leave in the message From 775b630dfab687bff880918ef153ebf7e5984bbd Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Fri, 27 Oct 2023 15:10:06 -0600 Subject: [PATCH 54/74] Add store_link test. --- .../ChadoStorageActions-FieldDefinitions.yml | 79 ++++++++- .../ChadoStorageActions_StoreLinkTest.php | 155 +++++++++++++++++- 2 files changed, 224 insertions(+), 10 deletions(-) diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml index be7b9816e..ce31b1400 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml @@ -361,6 +361,81 @@ testStoreActionDeleteIfEmpty: chado_table_alias: 'merry' chado_column: 'rank' -## Focus: -## Chado Table: +## Focus: Testing the basic functioning of the store_link action inccluding alias' where the base table +## is either on the left or right side of the relationship. +## Chado Table: projectprop testStoreLinkAction: + project: + field_name: 'project' + base_table: 'project' + properties: + record_id: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_id' + chado_table: 'project' + chado_column: 'project_id' + name_store: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'store' + chado_table: 'project' + chado_column: 'name' + right_linker: + field_name: 'right_linker' + base_table: 'project' + properties: + record_pkey: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_pkey' + chado_table: 'projectprop' + chado_table_alias: 'merry' + chado_column: 'projectprop_id' + fkey: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_link' + right_table: 'project' + right_table_id: 'project_id' + left_table: 'projectprop' + left_table_alias: 'merry' + left_table_id: 'project_id' + type: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'projectprop' + chado_table_alias: 'merry' + chado_column: 'type_id' + rank: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'projectprop' + chado_table_alias: 'merry' + chado_column: 'rank' + left_linker: + field_name: 'left_linker' + base_table: 'project' + properties: + record_pkey: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_pkey' + chado_table: 'projectprop' + chado_table_alias: 'pippin' + chado_column: 'projectprop_id' + fkey: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_link' + left_table: 'project' + left_table_id: 'project_id' + right_table: 'projectprop' + right_table_alias: 'pippin' + right_table_id: 'project_id' + type: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'projectprop' + chado_table_alias: 'pippin' + chado_column: 'type_id' + rank: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store' + chado_table: 'projectprop' + chado_table_alias: 'pippin' + chado_column: 'rank' diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreLinkTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreLinkTest.php index 933d5ce0a..8dedd3c78 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreLinkTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_StoreLinkTest.php @@ -28,6 +28,8 @@ class ChadoStorageActions_StoreLinkTest extends ChadoTestKernelBase { protected $yaml_file = __DIR__ . "/ChadoStorageActions-FieldDefinitions.yml"; + protected int $project_id; + /** * {@inheritdoc} */ @@ -60,8 +62,8 @@ protected function setUp() :void { /** * Test the store_link action. * - * Chado Table: - * Columns: + * Chado Table: projectprop + * Columns: projectprop_id*, project_id*, type_id*, value, rank* * * Specifically, ensure that a property with the store action * - @@ -69,12 +71,149 @@ protected function setUp() :void { public function testStoreLinkAction() { // Set the fields for this test and then re-populate the storage arrays. - // $this->setFieldsFromYaml($this->yaml_file, 'testStoreLinkAction'); - // $this->cleanChadoStorageValues(); + $this->setFieldsFromYaml($this->yaml_file, 'testStoreLinkAction'); + $this->cleanChadoStorageValues(); + + + $types_used = [ + 'right_linker' => $this->getCvtermId('schema', 'comment'), + 'left_linker' => $this->getCvtermId('schema', 'description'), + ]; + $total_num_records = 4; + + // Test Case: Insert valid values when they do not yet exist in Chado. + // --------------------------------------------------------- + $insert_values = [ + 'project' => [ + [ + 'record_id' => NULL, + 'name_store' => uniqid(), + ] + ], + 'right_linker' => [ + [ + 'record_pkey' => NULL, + 'fkey' => NULL, + 'type' => $types_used['right_linker'], + 'rank' => 0 + ], + [ + 'record_pkey' => NULL, + 'fkey' => NULL, + 'type' => $types_used['right_linker'], + 'rank' => 1 + ], + ], + 'left_linker' => [ + [ + 'record_pkey' => NULL, + 'fkey' => NULL, + 'type' => $types_used['left_linker'], + 'rank' => 0 + ], + [ + 'record_pkey' => NULL, + 'fkey' => NULL, + 'type' => $types_used['left_linker'], + 'rank' => 3 + ], + ], + ]; + $this->chadoStorageTestInsertValues($insert_values); + + $query = $this->chado_connection->select('1:projectprop', 'prop') + ->fields('prop', ['projectprop_id', 'project_id', 'type_id', 'rank']) + ->execute(); + $inserted_records = $query->fetchAll(); + $this->assertIsArray($inserted_records, + "We should have been able to select from the records from the projectprop table."); + $this->assertCount($total_num_records, $inserted_records, + "We did not get the number of records in the projectprop table that we excepted after insert."); + + // Ensure there are to records for each field. + foreach (['right_linker', 'left_linker'] as $field_name) { + $query = $this->chado_connection->select('1:projectprop', 'prop') + ->fields('prop', ['projectprop_id']) + ->condition('prop.type_id', $types_used[$field_name], '=') + ->orderBy('rank') + ->execute(); + $varname = $field_name . '_pkeys'; + $$varname = $query->fetchCol(); + $this->assertIsArray($$varname, + "We should have been able to select from the records from the projectprop table."); + $this->assertCount(2, $$varname, + "We did not get the number of records in the projectprop table for $field_name that we excepted after insert."); + } + + + // Test Case: Load values existing in Chado. + // --------------------------------------------------------- + // First we want to reset all the chado storage arrays to ensure we are + // doing a clean test. The values will purposefully remain in Chado but the + // Property Types, Property Values and Data Values will be built from scratch. + $this->cleanChadoStorageValues(); + + // For loading only the store id/pkey/link items should be populated. + $load_values = [ + 'project' => [ + [ + 'record_id' => 1, + ] + ], + 'right_linker' => [ + [ + 'record_pkey' => $right_linker_pkeys[0], + ], + [ + 'record_pkey' => $right_linker_pkeys[1], + ], + ], + 'left_linker' => [ + [ + 'record_pkey' => $left_linker_pkeys[0], + ], + [ + 'record_pkey' => $left_linker_pkeys[1], + ], + ], + ]; + $retrieved_values = $this->chadoStorageTestLoadValues($load_values); + + // Check that the store values in our fields have been loaded as they were inserted. + foreach ($insert_values as $field_name => $delta_records) { + if ($field_name == 'project') { continue; } + foreach ($delta_records as $delta => $expected_values) { + foreach(['fkey', 'type', 'rank'] as $property) { + $retrieved = $retrieved_values[$field_name][$delta][$property]['value']->getValue(); + $expected = $expected_values[$property]; + $this->assertEquals($expected, $retrieved, + "The value we retrieved for $field_name.$delta.$property did not match the one set with a store attribute during insert."); + } + } + } + + // Test Case: Update values in Chado using ChadoStorage. + // --------------------------------------------------------- + // When updating we need all the store id/pkey/link records + // and all values of the other properties. + $update_values = $insert_values; + $update_values['right_linker'][0]['record_pkey'] = $right_linker_pkeys[0]; + $update_values['right_linker'][1]['record_pkey'] = $right_linker_pkeys[1]; + $update_values['left_linker'][0]['record_pkey'] = $left_linker_pkeys[0]; + $update_values['left_linker'][1]['record_pkey'] = $left_linker_pkeys[1]; + // $update_values['right_linker'][0]['fkey'] = $update_values['right_linker'][1]['fkey'] = $update_values['left_linker'][0]['fkey'] = $update_values['left_linker'][1]['fkey'] = 1; + + // Let's test this without any changes. + $this->chadoStorageTestUpdateValues($update_values); + + $query = $this->chado_connection->select('1:projectprop', 'prop') + ->fields('prop', ['projectprop_id', 'project_id', 'type_id', 'rank']) + ->execute(); + $records = $query->fetchAll(); + $this->assertIsArray($records, + "We should have been able to select from the records from the projectprop table."); + $this->assertCount($total_num_records, $records, + "We did not get the number of records in the projectprop table that we excepted after update."); - // Stop here and mark this test as incomplete. - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); } } From a29daf4fffde7accf813442cfa290083566d43eb Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Fri, 27 Oct 2023 15:38:11 -0600 Subject: [PATCH 55/74] Fix for issue #1661 Co-authored-by: Douglas Senalik Co-authored-by: Lacey Sanderson --- tripal_chado/src/Database/ChadoSchema.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tripal_chado/src/Database/ChadoSchema.php b/tripal_chado/src/Database/ChadoSchema.php index db7b67139..c58442b80 100644 --- a/tripal_chado/src/Database/ChadoSchema.php +++ b/tripal_chado/src/Database/ChadoSchema.php @@ -20,8 +20,10 @@ public function getSchemaDef(array $parameters) :array { $source = $parameters['source'] ?? 'file'; $format = strtolower($parameters['format'] ?? ''); - $version = $parameters['version']; - if (!array_key_exists('version', $parameters) OR empty($parameters['version'])) { + if (array_key_exists('version', $parameters) and !empty($parameters['version'])) { + $version = $parameters['version']; + } + else { $version = $this->connection->getVersion(); } From 8d538ec05a976efb3c622ec8e4b61d3b84218734 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Fri, 27 Oct 2023 16:32:23 -0600 Subject: [PATCH 56/74] Add missing stock and arraydesign foreign keys. --- ..._chado.chado_term_mapping.core_mapping.yml | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/tripal_chado/config/install/tripal_chado.chado_term_mapping.core_mapping.yml b/tripal_chado/config/install/tripal_chado.chado_term_mapping.core_mapping.yml index 49b76cd86..1b2ed5956 100644 --- a/tripal_chado/config/install/tripal_chado.chado_term_mapping.core_mapping.yml +++ b/tripal_chado/config/install/tripal_chado.chado_term_mapping.core_mapping.yml @@ -139,7 +139,7 @@ tables: - name: 'value' term_id: 'NCIT:C25712' term_name: 'Value' - + - name: 'analysisprop' columns: - name: 'analysis_id' @@ -268,6 +268,9 @@ tables: - name: 'value' term_id: 'NCIT:C25712' term_name: 'Value' + - name: 'arraydesign_id' + term_id: 'EFO:0000269' + term_name: 'array design' - name: 'assay' columns: @@ -2504,6 +2507,9 @@ tables: - name: 'rank' term_id: 'OBCS:0000117' term_name: 'rank order' + - name: 'stock_id' + term_id: 'NCIT:C70699' + term_name: 'Biospecimen' - name: 'stock_cvtermprop' columns: @@ -2525,6 +2531,9 @@ tables: - name: 'is_current' term_id: 'local:is_current' term_name: 'is_current' + - name: 'stock_id' + term_id: 'NCIT:C70699' + term_name: 'Biospecimen' - name: 'stock_dbxrefprop' columns: @@ -2549,6 +2558,9 @@ tables: - name: 'type_id' term_id: 'schema:additionalType' term_name: 'additionalType' + - name: 'stock_id' + term_id: 'NCIT:C70699' + term_name: 'Biospecimen' - name: 'stock_featuremap' columns: @@ -2558,30 +2570,39 @@ tables: - name: 'type_id' term_id: 'schema:additionalType' term_name: 'additionalType' + - name: 'stock_id' + term_id: 'NCIT:C70699' + term_name: 'Biospecimen' - name: 'stock_genotype' columns: - name: 'genotype_id' term_id: 'NCIT:C16631' term_name: 'Genotype' + - name: 'stock_id' + term_id: 'NCIT:C70699' + term_name: 'Biospecimen' - name: 'stock_library' columns: - name: 'library_id' term_id: 'local:library' term_name: 'Library' + - name: 'stock_id' + term_id: 'NCIT:C70699' + term_name: 'Biospecimen' - name: 'stockprop' columns: + - name: 'stock_id' + term_id: 'NCIT:C70699' + term_name: 'Biospecimen' - name: 'rank' term_id: 'OBCS:0000117' term_name: 'rank order' - name: 'type_id' term_id: 'schema:additionalType' term_name: 'additionalType' - - - name: 'stockprop' - columns: - name: 'value' term_id: 'NCIT:C25712' term_name: 'Value' From 48eb23f54820cf1a84e1398fdbbde2d0ab4b16fd Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Fri, 27 Oct 2023 16:55:27 -0600 Subject: [PATCH 57/74] Add term to list to be created on install. --- .../tripal.tripal_content_terms.chado_content_terms.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tripal_chado/config/install/tripal.tripal_content_terms.chado_content_terms.yml b/tripal_chado/config/install/tripal.tripal_content_terms.chado_content_terms.yml index 80dc90908..033e9c8a2 100644 --- a/tripal_chado/config/install/tripal.tripal_content_terms.chado_content_terms.yml +++ b/tripal_chado/config/install/tripal.tripal_content_terms.chado_content_terms.yml @@ -775,7 +775,9 @@ vocabularies: - id: 'NCIT:C42699' name: 'Namespace' description: 'In general, a namespace is an abstract container, which is or could be filled by names, or technical terms, or words, and these represent or stand for real-world things. A description logic terminology namespace is a collection of Kind, Role, Property and Concept definitions. As in computer programming, context namespaces are intended to allow multiple knowledge bases to reside in the same physical database. (from Apelon) [ NCI ]' - + - id: 'NCIT:C70699' + name: 'Biospecimen' + description: 'Any material sample taken from a biological entity for testing, diagnostic, propagation, treatment or research purposes, including a sample obtained from a living organism or taken from the biological object after halting of all its life functions.' - name: 'ncbitaxon' label: 'NCBI organismal classification. An ontology representation of the NCBI organismal taxonomy' From d96eabcc28eeafd6eb3bf5687d977c8f808a1caa Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Tue, 31 Oct 2023 12:45:33 -0600 Subject: [PATCH 58/74] Ensure read_value/path use a unique alias to retrieve the value. --- .../src/Plugin/TripalStorage/ChadoStorage.php | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php index fcb2407ff..8d5e85df8 100644 --- a/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php +++ b/tripal_chado/src/Plugin/TripalStorage/ChadoStorage.php @@ -90,6 +90,20 @@ class ChadoStorage extends TripalStorageBase implements TripalStorageInterface { */ protected $reverse_alias_mapping = []; + /** + * A mapping of the field property to the alias used in the query. + * This is specific to properties with an action of read_value who + * specify a path. + * + * @var array + * a nested array where mapping the new alias including the right table alias + * to the original alias set in the property type. The structure is: + * [field name]: + * [property key]: + * [original column alias]: [new alias] + */ + protected $join_column_alias = []; + /** * Implements ContainerFactoryPluginInterface->create(). * @@ -462,7 +476,10 @@ public function selectChadoRecord(&$records, $base_tables, $chado_table_alias, $ foreach ($jinfo['columns'] as $column) { $sel_col = $column[0]; - $sel_col_as = $column[1]; + $sel_col_as = $ralias . '_' . $column[1]; + $field_name = $column[2]; + $property_key = $column[3]; + $this->join_column_alias[$field_name][$property_key][ $column[1] ] = $sel_col_as; $select->addField($ralias, $sel_col, $sel_col_as); } $j_index++; @@ -739,6 +756,9 @@ protected function setPropValues(&$values, $records) { // Get the values of properties that just want to read values. if (in_array($action, ['read_value', 'join'])) { + // Both variants should have a chado column defined so grab that first. + $chado_column = $prop_storage_settings['chado_column']; + $as = array_key_exists('as', $prop_storage_settings) ? $prop_storage_settings['as'] : $chado_column; if (array_key_exists('chado_table', $prop_storage_settings)) { $chado_table = $prop_storage_settings['chado_table']; $chado_table_alias = $this->getTableAliasForChadoTable($field_name, $key, $chado_table); @@ -757,9 +777,11 @@ protected function setPropValues(&$values, $records) { // The base table is the left table of the first part of the path. $chado_table = $left_table; $chado_table_alias = $left_table; + // the column alias will actually include the right table alias + // in order to keep the joins separate. + // So we will grab that here. + $as = $this->join_column_alias[$field_name][$key][$as]; } - $chado_column = $prop_storage_settings['chado_column']; - $as = array_key_exists('as', $prop_storage_settings) ? $prop_storage_settings['as'] : $chado_column; $value = $records[$chado_table_alias][$delta]['fields'][$as]; $values[$field_name][$delta][$key]['value']->setValue($value); } @@ -1356,7 +1378,7 @@ protected function buildChadoRecords_read_value(array &$records, int $delta, arr $path = $storage_settings['path']; $as = array_key_exists('as', $storage_settings) ? $storage_settings['as'] : $chado_column; $path_arr = explode(";", $path); - $this->addChadoRecordJoins($records, $chado_column, $as, $delta, $path_arr); + $this->addChadoRecordJoins($records, $chado_column, $as, $delta, $path_arr, $context['field_name'], $context['property_key']); } // Otherwise, it is a column in a base table. In this case, we // only need to ensure the column is added to the fields. @@ -1383,7 +1405,7 @@ protected function buildChadoRecords_read_value(array &$records, int $delta, arr * @param string $path */ protected function addChadoRecordJoins(array &$records, string $chado_column, string $as, - int $delta, array $path_arr, $parent_table = NULL, $parent_column = NULL, $depth = 0) { + int $delta, array $path_arr, string $field_name, string $property_key, $parent_table = NULL, $parent_column = NULL, $depth = 0) { // Get the left column and the right table join infor. list($left, $right) = explode(">", array_shift($path_arr)); @@ -1440,13 +1462,13 @@ protected function addChadoRecordJoins(array &$records, string $chado_column, st // We're done recursing if we only have no elements left in the path if (count($path_arr) == 0) { - $records[$parent_table][$delta]['joins'][$right_table][$parent_column]['columns'][] = [$chado_column, $as]; + $records[$parent_table][$delta]['joins'][$right_table][$parent_column]['columns'][] = [$chado_column, $as, $field_name, $property_key]; return; } // Add the right table back onto the path as the new left table and recurse. $depth++; - $this->addChadoRecordJoins($records, $chado_column, $as, $delta, $path_arr, $parent_table, $parent_column, $depth); + $this->addChadoRecordJoins($records, $chado_column, $as, $delta, $path_arr, $field_name, $property_key, $parent_table, $parent_column, $depth); } From 615faa8373dc02ccf1badf13b54f9728b066de54 Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Tue, 31 Oct 2023 14:51:32 -0600 Subject: [PATCH 59/74] Add automated tesing for this test case. --- .../ChadoStorageActions-FieldDefinitions.yml | 42 +++++++++ .../ChadoStorageActions_ReadValueTest.php | 85 +++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml index ce31b1400..55be0e6da 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions-FieldDefinitions.yml @@ -115,6 +115,48 @@ testReadValueActionJoin: chado_table: 'cvterm' chado_column: 'name' path: 'stock.stock_id>stock_cvterm.stock_id;stock_cvterm.cvterm_id>cvterm.cvterm_id' +# Ensure joins accessing the same column stay separate. +testReadValueActionJoinDouble: + test_join1: + field_name: 'test_join1' + base_table: 'arraydesign' + properties: + record_id: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_id' + chado_table: 'arraydesign' + chado_column: 'arraydesign_id' + type_id: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'arraydesign_id' + chado_table: 'arraydesign' + chado_column: 'platformtype_id' + accession_read: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'read_value' + chado_table: 'dbxref' + chado_column: 'accession' + path: 'arraydesign.platformtype_id>cvterm.cvterm_id;cvterm.dbxref_id>dbxref.dbxref_id' + test_join2: + field_name: 'test_join2' + base_table: 'arraydesign' + properties: + record_id: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'store_id' + chado_table: 'arraydesign' + chado_column: 'arraydesign_id' + type_id: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoIntStoragePropertyType' + action: 'arraydesign_id' + chado_table: 'arraydesign' + chado_column: 'substratetype_id' + accession_read: + propertyType class: 'Drupal\tripal_chado\TripalStorage\ChadoVarCharStoragePropertyType' + action: 'read_value' + chado_table: 'dbxref' + chado_column: 'accession' + path: 'arraydesign.substratetype_id>cvterm.cvterm_id;cvterm.dbxref_id>dbxref.dbxref_id' # Ensure read_value works when there isn't a store action for the same column. testReadValueActionNoStore: test_read: diff --git a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php index eb145a8cc..31c7bf8c9 100644 --- a/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php +++ b/tripal_chado/tests/src/Kernel/Plugin/ChadoStorage/ChadoStorageActions_ReadValueTest.php @@ -358,6 +358,91 @@ public function testReadValueActionJoin() { } } + /** + * Test read_value through a join where two fields access the same tables. + * + * Base Table: arraydesign + * Columns: arraydesign_id*, manufacturer_id, platformtype_id*, substratetype_id*, name + * Chado Table: dbxref + * Columns: accession + * + * Specically, testing that we can read the database reference for an arraydesign + * record through the arraydesign > cvterm > dbxref path for two separate + * fields without their being data swap between them. + * + * Again focusing on load since this action type does not impact insert/update. + */ + public function testReadValueActionJoinDouble() { + + // Set the fields for this test and then re-populate the storage arrays. + $this->setFieldsFromYaml($this->yaml_file, 'testReadValueActionJoinDouble'); + $this->cleanChadoStorageValues(); + + // Create the organism record needed for the stock. + $contact_id = $this->chado_connection->insert('1:contact') + ->fields([ + 'name' => uniqid(), + ]) + ->execute(); + $this->assertIsNumeric($contact_id, + 'We should have been able to insert a contact for use with testing.'); + // Create the arraydesign record needed for testing the load. + $platform_accession = 'comment'; + $substrate_accession = 'type'; + $arraydesign_expected = [ + 'manufacturer_id' => $contact_id, + 'platformtype_id' => $this->getCvtermId('rdfs', $platform_accession), + 'substratetype_id' => $this->getCvtermId('rdfs', $substrate_accession), + 'name' => uniqid(), + ]; + $arraydesign_id = $this->chado_connection->insert('1:arraydesign') + ->fields($arraydesign_expected) + ->execute(); + $this->assertIsNumeric($arraydesign_id, + 'We should have been able to insert a arraydesign record for use with testing.'); + + // For loading only the store id/pkey/link items should be populated. + $load_values = [ + 'test_join1' => [ + [ + 'record_id' => $arraydesign_id, + 'type_id' => $arraydesign_expected['platformtype_id'], + 'accession_read' => NULL, + ], + ], + 'test_join2' => [ + [ + 'record_id' => $arraydesign_id, + 'type_id' => $arraydesign_expected['substratetype_id'], + 'accession_read' => NULL, + ], + ], + ]; + $retrieved_values = $this->chadoStorageTestLoadValues($load_values); + + // Check that the accession in our fields have been loaded. + $delta = 0; + $ret = $retrieved_values['test_join1'][$delta]['accession_read']['value']->getValue(); + $this->assertEquals($platform_accession, $ret, + "The dbxref accession retrieved for test_join1 should match the one we inserted into chado for platformtype_id."); + $ret = $retrieved_values['test_join1'][$delta]['record_id']['value']->getValue(); + $this->assertEquals($arraydesign_id, $ret, + "The arraydesign_id retrieved should match the one we inserted into chado."); + $ret = $retrieved_values['test_join1'][$delta]['type_id']['value']->getValue(); + $this->assertEquals($arraydesign_expected['platformtype_id'], $ret, + "The type_id retrieved should match the one we inserted into chado for platformtype_id."); + + $ret = $retrieved_values['test_join2'][$delta]['accession_read']['value']->getValue(); + $this->assertEquals($substrate_accession, $ret, + "The dbxref accession retrieved for test_join2 should match the one we inserted into chado for substratetype_id."); + $ret = $retrieved_values['test_join2'][$delta]['record_id']['value']->getValue(); + $this->assertEquals($arraydesign_id, $ret, + "The arraydesign_id retrieved should match the one we inserted into chado."); + $ret = $retrieved_values['test_join2'][$delta]['type_id']['value']->getValue(); + $this->assertEquals($arraydesign_expected['substratetype_id'], $ret, + "The type_id retrieved should match the one we inserted into chado for substratetype_id."); + } + /** * Test read_value works when there is no store on the same column. * From 798b94ca998650dcca4a02cdf2b16f953c9495cc Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 1 Nov 2023 14:04:15 -0600 Subject: [PATCH 60/74] Ensure file upload is completely disabled. --- .../src/Plugin/TripalImporter/OBOImporter.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php index 888be53cb..1e9019281 100644 --- a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php +++ b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php @@ -17,12 +17,13 @@ * file_types = {"obo"}, * upload_description = @Translation("Please provide the details for importing a new OBO file. The file must have a .obo extension."), * upload_title = @Translation("New OBO File"), - * use_analysis = False, - * require_analysis = True, + * use_analysis = FALSE, + * require_analysis = FALSE, * button_text = @Translation("Import OBO File"), - * file_upload = False, - * file_remote = False, - * file_required = False, + * file_upload = FALSE, + * file_local = FALSE, + * file_remote = FALSE, + * file_required = FALSE, * ) */ class OBOImporter extends ChadoImporterBase { From 0bc640fd5cfb1e559bf8cd8a5d2c21ca18a3e597 Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 1 Nov 2023 14:57:48 -0600 Subject: [PATCH 61/74] Fix ajax error in ontology form by allowing dependency serialization. --- .../src/TripalImporter/TripalImporterBase.php | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tripal/src/TripalImporter/TripalImporterBase.php b/tripal/src/TripalImporter/TripalImporterBase.php index fdbbf3fc8..83a1e4c69 100644 --- a/tripal/src/TripalImporter/TripalImporterBase.php +++ b/tripal/src/TripalImporter/TripalImporterBase.php @@ -11,11 +11,32 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\ReplaceCommand; +use Drupal\Core\DependencyInjection\DependencySerializationTrait; + /** * Defines an interface for tripal impoerter plugins. */ abstract class TripalImporterBase extends PluginBase implements TripalImporterInterface { + /** + * Needed to allow AJAX on TripalImporter forms once Dependency injection is used. + * + * The error message implies that the log exception this trait is needed to + * solve is caused by the form serializing an object that has an indirect + * reference to the database connection (TripalImporter) and that we should + * adjust your code so that is not necessary. + * + * That said, the TripalImporterForm does not appear to save the TripalImporter + * object in the form or form state at any point. Instead it only uses + * the importer object to get strings and arrays that are incorporated + * into the form. + * + * Anyway, using this trait solves the problem and although the error + * mentions this should be a temporary solution, there are no mentioned plans + * in the Drupal forumns or code that this trait will be removed at any point. + */ + use DependencySerializationTrait; + /** * The number of items that this importer needs to process. A progress * can be calculated by dividing the number of items process by this From 4ac82363c804d1d6eeeb3e9f1fdaf5a35f741b54 Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 1 Nov 2023 15:44:47 -0600 Subject: [PATCH 62/74] Switch ajax calls to use static methods so the db connection is not serialized. --- tripal_chado/src/Plugin/TripalImporter/OBOImporter.php | 4 ++-- tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php index 1e9019281..60906128f 100644 --- a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php +++ b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php @@ -220,7 +220,7 @@ private function formExistingOBOElements(&$form, &$form_state) { '#options' => $obos, '#default_value' => $obo_id, '#ajax' => [ - 'callback' => [$this, 'formAjaxCallback'], + 'callback' => [$this::class, 'formAjaxCallback'], 'wrapper' => 'obo-existing-fieldset', ], '#description' => t('Select a vocabulary to import.'), @@ -374,7 +374,7 @@ private function formNewOBOElements(&$form, &$form_state) { * @param \Drupal\Core\Form\FormStateInterface $form_state * The form state object. */ - public function formAjaxCallback($form, &$form_state) { + public static function formAjaxCallback($form, &$form_state) { $uobo_name = $form['obo_existing']['uobo_name']['#default_value']; $uobo_url = $form['obo_existing']['uobo_url']['#default_value']; diff --git a/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php b/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php index f71c42ca4..42bbfb35d 100644 --- a/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php +++ b/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php @@ -92,7 +92,7 @@ public function form($form, &$form_state) { ))->toString() . '.', '#default_value' => \Drupal::state()->get('tripal_ncbi_api_key', NULL), '#ajax' => array( - 'callback' => [$this, 'tripal_taxon_importer_set_ncbi_api_key'], + 'callback' => [$this::class, 'tripal_taxon_importer_set_ncbi_api_key'], 'wrapper' => 'ncbi_api_key', 'disable-refocus' => true, ), @@ -1169,7 +1169,7 @@ public function formSubmit($form, &$form_state) { * @return array * The new api key field. */ - function tripal_taxon_importer_set_ncbi_api_key($form, &$form_state) { + public static function tripal_taxon_importer_set_ncbi_api_key($form, &$form_state) { $key_value = $form_state->getValue(['ncbi_api_key']); \Drupal::state()->set('tripal_ncbi_api_key', \Drupal\Component\Utility\HTML::escape($key_value)); \Drupal::messenger()->addMessage(t('NCBI API key has been saved successfully!')); From 95740d5f6679a0749b73cf118a3cbc5e0b1d0d9d Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 1 Nov 2023 15:55:39 -0600 Subject: [PATCH 63/74] Deprecated to pass an empty string to trim. --- .../src/Plugin/TripalImporter/OBOImporter.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php index 60906128f..2992e31ea 100644 --- a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php +++ b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php @@ -396,12 +396,18 @@ public function formSubmit($form, &$form_state) { $public = \Drupal::database(); $obo_id = $form_state->getValue('obo_id'); - $obo_name = trim($form_state->getValue('obo_name')); - $obo_url = trim($form_state->getValue('obo_url')); - $obo_file = trim($form_state->getValue('obo_file')); - $uobo_name = trim($form_state->getValue('uobo_name')); - $uobo_url = trim($form_state->getValue('uobo_url')); - $uobo_file = trim($form_state->getValue('uobo_file')); + $obo_name = $form_state->getValue('obo_name'); + $obo_url = $form_state->getValue('obo_url'); + $obo_file = $form_state->getValue('obo_file'); + $uobo_name = $form_state->getValue('uobo_name'); + $uobo_url = $form_state->getValue('uobo_url'); + $uobo_file = $form_state->getValue('uobo_file'); + // Now trim variables. We do it this way to avoid trimming an empty value. + foreach(['obo_name', 'obo_url', 'obo_file', 'uobo_name', 'uobo_url', 'uobo_file'] as $varname) { + if (!empty($$varname)) { + $$varname = trim($$varname); + } + } // If the user requested to alter the details then do that. From 1f45665c580e7c32a0850d44c636d68bcd4ae94f Mon Sep 17 00:00:00 2001 From: Lacey-Anne Sanderson Date: Wed, 1 Nov 2023 16:03:34 -0600 Subject: [PATCH 64/74] Ensure any modifications made by the importer are used to create the job. --- tripal/src/Form/TripalImporterForm.php | 32 ++++++++++++++------------ 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/tripal/src/Form/TripalImporterForm.php b/tripal/src/Form/TripalImporterForm.php index 8fe5732ed..636f2fe83 100644 --- a/tripal/src/Form/TripalImporterForm.php +++ b/tripal/src/Form/TripalImporterForm.php @@ -170,6 +170,23 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $importer = $importer_manager->createInstance($plugin_id); $importer_def = $importer_manager->getDefinitions()[$plugin_id]; + // Now allow the loader to do its own submit if needed. + try { + $importer->formSubmit($form, $form_state); + // Ensure any modifications made by the importer are used. + $form_values = $form_state->getValues(); + $run_args = $form_values; + } + catch (\Exception $e) { + \Drupal::messenger()->addMessage('Cannot submit import: ' . $e->getMessage(), 'error'); + } + + // If the importer wants to rebuild the form for some reason then let's + // not add a job. + if ($form_state->isRebuilding() == TRUE) { + return; + } + // Remove the file_local and file_upload args. We'll add in a new // full file path and the fid instead. unset($run_args['file_local']); @@ -218,23 +235,8 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $file_details['file_remote'] = $file_remote; } try { - // Now allow the loader to do its own submit if needed. - $importer->formSubmit($form, $form_state); - // If the formSubmit made changes to the $form_state we need to update the - // $run_args info. - if ($run_args !== $form_values) { - $run_args = $form_values; - } - - // If the importer wants to rebuild the form for some reason then let's - // not add a job. - if ($form_state->isRebuilding() == TRUE) { - return; - } - $importer->createImportJob($run_args, $file_details); $importer->submitJob(); - } catch (\Exception $e) { \Drupal::messenger()->addMessage('Cannot submit import: ' . $e->getMessage(), 'error'); From 15e6892348e463e90dc5a791876bbccba27ab608 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Thu, 2 Nov 2023 10:09:36 -0600 Subject: [PATCH 65/74] Fix remote lookup of ontology short name. --- .../src/Plugin/TripalImporter/OBOImporter.php | 70 ++++++++++--------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php index 2992e31ea..3282c3e4f 100644 --- a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php +++ b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php @@ -4,9 +4,11 @@ use Drupal\tripal_chado\TripalImporter\ChadoImporterBase; use Drupal\tripal\TripalVocabTerms\TripalTerm; +use Drupal\Component\Serialization\Json; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\InvokeCommand; use Drupal\Core\Ajax\ReplaceCommand; + /** * OBO Importer implementation of the TripalImporterBase. * @@ -1312,7 +1314,7 @@ private function findEBITerm($id) { $this->setInterval(1); } - $this->logger->notice(t("Performing EBI OLS Lookup for: @id", ['@id' => $id])); + $this->logger->notice('Performing EBI OLS Lookup for: @id', ['@id' => $id]); // Get the short name and accession for the term. $pair = explode(":", $id, 2); @@ -1328,21 +1330,31 @@ private function findEBITerm($id) { list($ontologyID, $base_iri) = $this->baseIRIs[$short_name]; } else { - $ontology_results = $this->oboEbiLookup($id, 'query'); + $ontology_results = $this->oboEbiLookup($ontologyID, 'query'); + if ($ontology_results === FALSE OR !is_array($ontology_results)) { + throw new \Exception(t('Did not get a response from EBI OLS trying to lookup ontology: !id', + ['!id' => $ontologyID])); + } // If results were received but the number of results is 0, do a query-non-local lookup. if ($ontology_results['response']['numFound'] == 0) { - $ontology_results = $this->oboEbiLookup($id, 'query-non-local'); + $ontology_results = $this->oboEbiLookup($ontologyID, 'query-non-local'); } - if (!$ontology_results) { - throw new \Exception(t('Did not get a response from EBI OLS trying to lookup ontology: !id', - ['!id' => $id])); - } - if ($ontology_results['error']) { + if (array_key_exists('error', $ontology_results) AND !empty($ontology_results['error'])) { $message = t('Cannot find the ontology via an EBI OLS lookup: @short_name. ' . 'EBI Reported: @message. Consider finding the OBO file for this ' . ' ontology and manually loading it first.', ['@message' => $ontology_results['message'], '@short_name' => $short_name]); - $this->logger->warning($message); + $this->logger->error($message); + throw new \Exception('Unable to lookup ontology via EBI. See previous error for details.'); + } + // If results were received but the number of results is 0 and we already + // tried a query-non-local lookup then we just have to admin defeat. + if ($ontology_results['response']['numFound'] == 0) { + $this->logger->error('Cannot find the ontology via an EBI OLS lookup: @short_name. ' . + 'While EBI did not provide an error, no results were found. Consider ' . + ' finding the OBO file for this ontology and manually loading it first.', + ['@short_name' => $short_name]); + throw new \Exception('Unable to lookup ontology via EBI. See previous error for details.'); } // The following foreach code works but, I am not sure that // I am retrieving each query result from the json associative @@ -2861,6 +2873,8 @@ private function addComment($id, $cvterm_id, $comment, $rank) { * @ingroup tripal_obo_loader */ private function oboEbiLookup($accession, $type_of_search, $found_iri = NULL, $found_ontology = NULL) { + $client = \Drupal::httpClient(); + // Grab just the ontology from the $accession. $parts = explode(':', $accession); $ontology = strtolower($parts[0]); @@ -2879,55 +2893,43 @@ private function oboEbiLookup($accession, $type_of_search, $found_iri = NULL, $f } $full_url = 'http://www.ebi.ac.uk/ols/api/ontologies/' . $ontology . '/' . $type . '/' . $found_iri; $options = []; - $response = drupal_http_request($full_url, $options); - if (!empty($response)) { - $response = drupal_json_decode($response->data); - } } elseif ($type_of_search == 'ontology') { $options = []; $full_url = 'http://www.ebi.ac.uk/ols/api/ontologies/' . $ontology; - $response = drupal_http_request($full_url, $options); - if (!empty($response)) { - $response = drupal_json_decode($response->data); - } } elseif ($type_of_search == 'term') { // The IRI of the terms, this value must be double URL encoded $iri = urlencode(urlencode("http://purl.obolibrary.org/obo/" . str_replace(':', '_', $accession))); $options = []; $full_url = 'http://www.ebi.ac.uk/ols/api/ontologies/' . $ontology . '/' . 'terms/' . $iri; - $response = drupal_http_request($full_url, $options); - if (!empty($response)) { - $response = drupal_json_decode($response->data); - } } elseif ($type_of_search == 'property') { // The IRI of the terms, this value must be double URL encoded $iri = urlencode(urlencode("http://purl.obolibrary.org/obo/" . str_replace(':', '_', $accession))); $options = []; $full_url = 'http://www.ebi.ac.uk/ols/api/ontologies/' . $ontology . '/' . 'properties/' . $iri; - $response = drupal_http_request($full_url, $options); - if (!empty($response)) { - $response = drupal_json_decode($response->data); - } } elseif ($type_of_search == 'query') { $options = []; $full_url = 'http://www.ebi.ac.uk/ols/api/search?q=' . $accession . '&queryFields=obo_id&local=true'; - $response = drupal_http_request($full_url, $options); - if (!empty($response)) { - $response = drupal_json_decode($response->data); - } } elseif ($type_of_search == 'query-non-local') { $options = []; $full_url = 'http://www.ebi.ac.uk/ols/api/search?q=' . $accession . '&queryFields=obo_id'; - $response = drupal_http_request($full_url, $options); - if (!empty($response)) { - $response = drupal_json_decode($response->data); - } } - return $response; + + try { + $response = $client->get($full_url, $options); + $response = $response->getBody(); + $response = Json::decode($response); + return $response; + } + catch (RequestException $e) { + $this->logger->error('Unable to get response from @url when trying to retrieve data for @accession. @exception', + ['@url' => $full_url, '@accession' => $accession, '@exception' => $e->getMessage()]); + } + + return FALSE; } } From 58670f505ec85228ba772f309e8a1c7d13b9a7c8 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Thu, 2 Nov 2023 13:54:58 -0600 Subject: [PATCH 66/74] Ensure term stanza's have a name and id. --- .../src/Plugin/TripalImporter/OBOImporter.php | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php index 3282c3e4f..8a17fa5da 100644 --- a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php +++ b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php @@ -1330,14 +1330,14 @@ private function findEBITerm($id) { list($ontologyID, $base_iri) = $this->baseIRIs[$short_name]; } else { - $ontology_results = $this->oboEbiLookup($ontologyID, 'query'); + $ontology_results = $this->oboEbiLookup($id, 'query'); if ($ontology_results === FALSE OR !is_array($ontology_results)) { throw new \Exception(t('Did not get a response from EBI OLS trying to lookup ontology: !id', ['!id' => $ontologyID])); } // If results were received but the number of results is 0, do a query-non-local lookup. if ($ontology_results['response']['numFound'] == 0) { - $ontology_results = $this->oboEbiLookup($ontologyID, 'query-non-local'); + $ontology_results = $this->oboEbiLookup($id, 'query-non-local'); } if (array_key_exists('error', $ontology_results) AND !empty($ontology_results['error'])) { $message = t('Cannot find the ontology via an EBI OLS lookup: @short_name. ' . @@ -1409,7 +1409,7 @@ private function findEBITerm($id) { } // If EBI sent an error message then throw an error. - if ($results['error']) { + if (array_key_exists('error', $results) AND !empty($results['error'])) { $message = t('Cannot find the term via an EBI OLS lookup: @term. EBI ' . 'Reported: @message. Consider finding the OBO file for this ontology ' . 'and manually loading it first.', ['@message' => $results['message'], '@term' => $id]); @@ -1424,7 +1424,7 @@ private function findEBITerm($id) { // Make an OBO stanza array as if this term were in the OBO file and // return it. - $this->logMessage("Found @term in EBI OLS.", ['@term' => $id]); + $this->logger->notice("Found @term in EBI OLS.", ['@term' => $id]); $stanza = []; $stanza['id'][0] = $id; $stanza['name'][0] = $results['label']; @@ -2387,15 +2387,27 @@ private function parse($obo_file, &$header) { } } - // Before caching this stanza, check the term's name to - // make sure it doesn't conflict. If it does we'll just - // add the ID to the name to ensure it doesn't. - if (array_key_exists($stanza['name'][0], $this->term_names)) { - $new_name = $stanza['name'][0] . '(' . $stanza['id'][0] . ')'; - $stanza['name'][0] = $new_name; + // Before caching this stanza... + // We need to ensure this term has an id. + // This one is non-negotiable! + if (!array_key_exists('id', $stanza)) { + $this->logger('We are skipping the following term because it does not have and id. Term information: ' . print_r($stanza, TRUE)); } + else { + // We need to ensure this term has a name. + // If it doesn't then we will use the id. + if (!array_key_exists('name', $stanza)) { + $stanza['name'][0] = $stanza['id'][0]; + } + // make sure it doesn't conflict. If it does we'll just + // add the ID to the name to ensure it doesn't. + if (array_key_exists($stanza['name'][0], $this->term_names)) { + $new_name = $stanza['name'][0] . '(' . $stanza['id'][0] . ')'; + $stanza['name'][0] = $new_name; + } - $this->cacheTermStanza($stanza, $type); + $this->cacheTermStanza($stanza, $type); + } } From 340ccac0e8fff3a2a4fc6fa3413877a308c6fa22 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Thu, 2 Nov 2023 13:57:34 -0600 Subject: [PATCH 67/74] Set a default definition for the term if one is not available. --- tripal_chado/src/Plugin/TripalImporter/OBOImporter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php index 8a17fa5da..a8e21f52a 100644 --- a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php +++ b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php @@ -1428,7 +1428,7 @@ private function findEBITerm($id) { $stanza = []; $stanza['id'][0] = $id; $stanza['name'][0] = $results['label']; - $stanza['def'][0] = $results['def']; + $stanza['def'][0] = (array_key_exists('def', $results)) ? $results['def'] : ''; $stanza['namespace'][0] = $results['ontology_name']; $stanza['is_obsolete'][0] = $results['is_obsolete'] ? 'true' : ''; $stanza['is_relationshiptype'][0] = ''; From f4143ff5f14e569cabf4e118dd9d7fbc83570c45 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Thu, 2 Nov 2023 14:41:35 -0600 Subject: [PATCH 68/74] Fix call to logger. --- tripal_chado/src/Plugin/TripalImporter/OBOImporter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php index a8e21f52a..fa6db3bad 100644 --- a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php +++ b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php @@ -2391,7 +2391,7 @@ private function parse($obo_file, &$header) { // We need to ensure this term has an id. // This one is non-negotiable! if (!array_key_exists('id', $stanza)) { - $this->logger('We are skipping the following term because it does not have and id. Term information: ' . print_r($stanza, TRUE)); + $this->logger->warning('We are skipping the following term because it does not have and id. Term information: ' . print_r($stanza, TRUE)); } else { // We need to ensure this term has a name. From 3605d1b2ba38e9d7fa5533a47ca48b03bff9b446 Mon Sep 17 00:00:00 2001 From: Lacey Sanderson Date: Fri, 3 Nov 2023 11:19:56 -0600 Subject: [PATCH 69/74] Ensure cvterm details for existing terms are properly pulled out. --- tripal_chado/src/Plugin/TripalImporter/OBOImporter.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php index fa6db3bad..3c4b98592 100644 --- a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php +++ b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php @@ -2050,13 +2050,13 @@ private function lookupTerm($short_name, $accession) { // Create a new stanza using the values of this cvterm. $stanza = []; $stanza['id'][0] = $short_name . ':' . $accession; - $stanza['name'][0] = $cvterm->getValue('name'); - $stanza['def'][0] = $cvterm->getValue('definition'); - $stanza['namespace'][0] = $cv->getValue('name'); - $stanza['is_obsolete'][0] = $cvterm->getValue('is_obsolete') == 1 ? 'true' : ''; + $stanza['name'][0] = $cvterm->name; + $stanza['def'][0] = $cvterm->definition; + $stanza['namespace'][0] = $cv->name; + $stanza['is_obsolete'][0] = ($cvterm->is_obsolete == 1) ? 'true' : ''; $stanza['is_relationshiptype'][0] = ''; $stanza['db_name'][0] = $db->name; - $stanza['cv_name'][0] = $cv->getValue('name'); + $stanza['cv_name'][0] = $cv->name; return $stanza; } From 616f892eb41cdf3a841f340690c164c5d5b4e489 Mon Sep 17 00:00:00 2001 From: Douglas Senalik Date: Mon, 6 Nov 2023 09:08:41 -0600 Subject: [PATCH 70/74] typo fix --- tripal_chado/src/Plugin/TripalImporter/OBOImporter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php index 3c4b98592..64443cf82 100644 --- a/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php +++ b/tripal_chado/src/Plugin/TripalImporter/OBOImporter.php @@ -2391,7 +2391,7 @@ private function parse($obo_file, &$header) { // We need to ensure this term has an id. // This one is non-negotiable! if (!array_key_exists('id', $stanza)) { - $this->logger->warning('We are skipping the following term because it does not have and id. Term information: ' . print_r($stanza, TRUE)); + $this->logger->warning('We are skipping the following term because it does not have an id. Term information: ' . print_r($stanza, TRUE)); } else { // We need to ensure this term has a name. From f2111fe07e2e0bb2ff6c7b4cc967bc2a45cca0cd Mon Sep 17 00:00:00 2001 From: dsenalik Date: Mon, 6 Nov 2023 14:11:35 -0600 Subject: [PATCH 71/74] Do not display fopen error messages --- tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php b/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php index 42bbfb35d..d024f2cd7 100644 --- a/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php +++ b/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php @@ -557,7 +557,7 @@ private function updateExisting($root_taxon = NULL) { while (($retries > 0) and (!$rfh)) { $start = microtime(TRUE); // Get the search response from NCBI. - $rfh = fopen($search_url, "r"); + $rfh = @fopen($search_url, "r"); // If error, delay then retry if ((!$rfh) and ($retries)) { $this->logger->warning("Error contacting NCBI to look up @sci_name, will retry", @@ -810,7 +810,7 @@ private function importRecord($taxid, $root_taxon = NULL, $organism = NULL) { $retries = 3; while (($retries > 0) and (!$rfh)) { $start = microtime(TRUE); - $rfh = fopen($fetch_url, "r"); + $rfh = @fopen($fetch_url, "r"); if ($rfh) { $xml_text = ''; while (!feof($rfh)) { From b4e0ebcf6b30e80074fcb7688d140c930ad32864 Mon Sep 17 00:00:00 2001 From: dsenalik Date: Mon, 6 Nov 2023 15:01:07 -0600 Subject: [PATCH 72/74] temporarily force an error condition --- tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php b/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php index d024f2cd7..846b2f625 100644 --- a/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php +++ b/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php @@ -551,6 +551,7 @@ private function updateExisting($root_taxon = NULL) { if (!empty($api_key)) { $search_url .= "&api_key=" . $api_key; } +$ffh = fopen('https://will.fail. .surely', "r"); // Try to trigger the failure but not affect loading $rfh = NULL; // Query NCBI. To accomodate occasional glitches, retry up to three times. $retries = 3; From ac0008cf2b1da42482c47fe1ec4a711f7567dbca Mon Sep 17 00:00:00 2001 From: dsenalik Date: Mon, 6 Nov 2023 15:36:41 -0600 Subject: [PATCH 73/74] temporarily force an error condition --- tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php b/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php index 846b2f625..365317ca4 100644 --- a/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php +++ b/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php @@ -807,6 +807,7 @@ private function importRecord($taxid, $root_taxon = NULL, $organism = NULL) { // Query NCBI. To accomodate occasional glitches, retry up to three times. $xml = FALSE; +$ffh = fopen('https://will.fail. .surely', "r"); // Try to trigger the failure but not affect loading $rfh = NULL; $retries = 3; while (($retries > 0) and (!$rfh)) { From 43b14037bdb87c42ac9e9ce4890334a0df6e01d4 Mon Sep 17 00:00:00 2001 From: dsenalik Date: Mon, 6 Nov 2023 16:40:27 -0600 Subject: [PATCH 74/74] Remove temporary testing code --- tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php b/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php index 365317ca4..d024f2cd7 100644 --- a/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php +++ b/tripal_chado/src/Plugin/TripalImporter/TaxonomyImporter.php @@ -551,7 +551,6 @@ private function updateExisting($root_taxon = NULL) { if (!empty($api_key)) { $search_url .= "&api_key=" . $api_key; } -$ffh = fopen('https://will.fail. .surely', "r"); // Try to trigger the failure but not affect loading $rfh = NULL; // Query NCBI. To accomodate occasional glitches, retry up to three times. $retries = 3; @@ -807,7 +806,6 @@ private function importRecord($taxid, $root_taxon = NULL, $organism = NULL) { // Query NCBI. To accomodate occasional glitches, retry up to three times. $xml = FALSE; -$ffh = fopen('https://will.fail. .surely', "r"); // Try to trigger the failure but not affect loading $rfh = NULL; $retries = 3; while (($retries > 0) and (!$rfh)) {