From 7f6cd39e68415c61dcb5995e243ace7a51614950 Mon Sep 17 00:00:00 2001 From: Vlad Dracula Date: Thu, 18 Jan 2018 15:28:42 -0500 Subject: [PATCH 1/6] init property changing form --- includes/tripal_alchemist.api.inc | 15 +- includes/tripal_alchemist_converter.form.inc | 2 +- ...ipal_alchemist_property_converter.form.inc | 138 ++++++++++++++++++ tripal_alchemist.module | 20 +++ 4 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 includes/tripal_alchemist_property_converter.form.inc diff --git a/includes/tripal_alchemist.api.inc b/includes/tripal_alchemist.api.inc index 496a768..c8dee97 100644 --- a/includes/tripal_alchemist.api.inc +++ b/includes/tripal_alchemist.api.inc @@ -233,9 +233,9 @@ function tripal_alchemist_fetch_current_bundle_entities($bundle) { } -function tripal_alchemist_fetch_elligible_bundle_entities() { - -} +//function tripal_alchemist_fetch_elligible_bundle_entities() { +// +//} function function_tripal_alchemist_get_bundle($bundle_id) { @@ -243,4 +243,13 @@ function function_tripal_alchemist_get_bundle($bundle_id) { $query = "SELECT TB.name, TB.label FROM public.tripal_bundle TB WHERE TB.id = :bundle_id"; $result = db_query($query, [':bundle_id' => $bundle_id])->fetchObject(); return $result; +} + +function tripal_alchemist_get_all_entities_from_bundle($bundle) { + + $base_table = $bundle->table; + $tb_table = "chado_" . $bundle->name; + + $query = db_select($tb_table, 'tb'); + } \ No newline at end of file diff --git a/includes/tripal_alchemist_converter.form.inc b/includes/tripal_alchemist_converter.form.inc index 5f4048d..be5fb0b 100644 --- a/includes/tripal_alchemist_converter.form.inc +++ b/includes/tripal_alchemist_converter.form.inc @@ -21,7 +21,7 @@ function tripal_alchemist_converter_form($form, &$form_state) { $form['instructions'] = [ '#markup' => '

Welcome to Tripal Alchemist. This module is designed to convert Tripal Entities from one type to another. Your destination bundle must already exist before transmuting.

Please note that Tripal Alchemist will only convert Tripal 3 Entities. Tripal 2 content types (nodes) must be migrated.

Full documentation of this module is available on the projects Github page.

-', + ', ]; $form['source_bundle'] = [ diff --git a/includes/tripal_alchemist_property_converter.form.inc b/includes/tripal_alchemist_property_converter.form.inc new file mode 100644 index 0000000..18bd7d4 --- /dev/null +++ b/includes/tripal_alchemist_property_converter.form.inc @@ -0,0 +1,138 @@ + '

Welcome to Tripal Alchemist property converter. + +This form will allow you to modify the properties of selected analyses so that they will be elligible to be transformed to new content types. +

Content types that share a chado table have a type, either via a property linker table or a type_id column. This tool will allow you to change existing entries to match a new type, so that they can be converted.

+

Full documentation of this module is available on the projects Github page.

+ ', + ]; + + + //Fetch all bundles + + $all_bundles_object = tripal_alchemist_get_all_bundles(); + + $all_bundles_array = []; + $bundle_options = []; + + foreach ($all_bundles_object as $bundle) { + //Do I really need to do this? + if ($bundle->type != 'TripalEntity') { + continue; + } + $bundle_options[$bundle->id] = $bundle->label; + $all_bundles_array[$bundle->id] = $bundle; + } + + + + $form['source_bundle'] = [ + '#type' => 'select', + '#title' => t('Source Bundle'), + '#description' => t('The source bundle, which contains the entities you would like to transform.'), + '#empty_option' => t('- Select -'), + '#options' => $bundle_options, + '#default_value' => NULL, + '#ajax' => [ + 'callback' => 'tripal_alchemist_source_bundle_callback', + 'wrapper' => 'destination_bundle_wrapper', + 'effect' => 'fade', + ], + ]; + + + //create the divs for AJAX rebuilding. One for the destination bundle select, one for the transaction overview + $form['div1'] = [ + '#type' => 'fieldset', + '#collapsible' => FALSE, + '#prefix' => '
', + '#suffix' => '
', + ]; + + + $source_bundle = "analysis"; + + $source_options = tripal_alchemist_get_all_entities_from_bundle($source_bundle); + + + $selected_base_table = isset($form_state['values']['source_bundle']) ? $form_state['values']['source_bundle'] : NULL; + + if (!$selected_base_table) { + $form['div1']['instructions_no_select'] = [ + '#markup' => '

Destination Bundle

First, select a Source Bundle above. You will then be able to choose a destination bundle from al bundles sharing a base table.

', + ]; + return $form; + } + + $source_bundle = $all_bundles_array[$selected_base_table]; + $source_table = $source_bundle->data_table; + + //How many records here? + + $source_count = tripal_alchemist_fetch_current_bundle_entities($source_bundle); + + + if (!$source_count) { + $form['div1']['feedback'] = [ + '#markup' => "

Your selected source bundle $source_bundle->label has no entities in the database. You must populate the source bundle first, either by creating content or migrating Tripal 2 nodes.

", + ]; + } + $form['div1']['feedback'] = [ + '#markup' => "

There are $source_count records in the $source_bundle->label bundle.

", + ]; + + + //Create dropdown list of bundles for source that match that table + + $matching_destination_bundles = tripal_alchemist_get_matching_bundles($source_table); + unset($matching_destination_bundles[$selected_base_table]);//remove the source bundle + + if (count($matching_destination_bundles) == 0) { + $form['div1']['instructions_no_matches'] = [ + '#markup' => "

Your selected source bundle is the only bundle using the base table $source_table.

Please select a different source bundle, or define a new bundle with the same base table to serve as your destination bundle.

", + ]; + return $form; + } + + $form['div1']['destination_bundle'] = [ + '#type' => 'select', + '#title' => t('Destination Bundle'), + '#description' => t('Destination bundle. Your selected entities will be converted to Tripal Entities of this bundle type.'), + '#default' => NULL, + '#empty_option' => t('- Select -'), + '#options' => $matching_destination_bundles, + '#ajax' => [ + 'callback' => 'tripal_alchemist_properties_destination_bundle_callback', + 'wrapper' => 'report_on_migrations_wrapper', + ], + ]; + + + $selected_destination = isset($form_state['values']['destination_bundle']) ? $form_state['values']['destination_bundle'] : NULL; + + $destination_bundle = $all_bundles_array[$selected_destination]; + + + $source_options = tripal_alchemist_get_all_entities_from_bundle($source_bundle); + + $header = ['entity_id', 'name']; + + $form['div2']['select_entities_to_convert'] = [ + '#type' => 'tableselect', + '#header' => $header, + '#options' => $options, + '#multiple' => TRUE + + ]; + + return($form); +} + + +function tripal_alchemist_properties_destination_bundle_callback($form) { + return $form['div1']; +} \ No newline at end of file diff --git a/tripal_alchemist.module b/tripal_alchemist.module index 6303020..f7b2da0 100644 --- a/tripal_alchemist.module +++ b/tripal_alchemist.module @@ -19,6 +19,26 @@ function tripal_alchemist_menu() { 'file_path' => drupal_get_path('module', 'tripal_alchemist'), ]; + $items[$admin_url_base . "/entity_converter"] = [ + 'title' => 'Tripal Alchemist', + 'description' => t('Tripal Alchemist: Convert Tripal 3 Entities'), + 'access arguments' => [' tripal alchemist'], + 'page callback' => 'drupal_get_form', + 'page arguments' => ['tripal_alchemist_converter_form'], + 'file' => 'includes/tripal_alchemist_converter.form.inc', + 'file_path' => drupal_get_path('module', 'tripal_alchemist'), + ]; + + $items[$admin_url_base . "/property_converter"] = [ + 'title' => 'Tripal Alchemist Property Converter', + 'description' => t('Prepare your entities for conversion by altering their properties.'), + 'access arguments' => [' tripal alchemist'], + 'page callback' => 'drupal_get_form', + 'page arguments' => ['tripal_alchemist_property_converter_form'], + 'file' => 'includes/tripal_alchemist_property_converter.form.inc', + 'file_path' => drupal_get_path('module', 'tripal_alchemist'), + ]; + return $items; } From 7b27ea2cfb2647b4377d40d4bf969d3b7f3d9013 Mon Sep 17 00:00:00 2001 From: Vlad Dracula Date: Fri, 19 Jan 2018 16:38:13 -0500 Subject: [PATCH 2/6] reinit form --- includes/tripal_alchemist_converter.form.inc | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/includes/tripal_alchemist_converter.form.inc b/includes/tripal_alchemist_converter.form.inc index 8e7e316..8bb009e 100644 --- a/includes/tripal_alchemist_converter.form.inc +++ b/includes/tripal_alchemist_converter.form.inc @@ -19,7 +19,7 @@ function tripal_alchemist_converter_form($form, &$form_state) { } $form['instructions'] = [ - '#markup' => '

Welcome to Tripal Alchemist. This module is designed to convert Tripal Entities from one type to another. Your destination bundle must already exist before transmuting.

Please note that Tripal Alchemist will only convert Tripal 3 Entities. Tripal 2 content types (nodes) must be migrated.

+ '#markup' => '

Welcome to Tripal Alchemist. This module is designed to convert Tripal Entities from one type to another (a process called "transmutation" in clasical alchemy). Your destination bundle must already exist before transmuting.

Please note that Tripal Alchemist will only convert Tripal 3 Entities. Tripal 2 content types (nodes) must be migrated.

Full documentation of this module is available on the projects Github page.

', ]; @@ -39,6 +39,20 @@ function tripal_alchemist_converter_form($form, &$form_state) { ]; + $form['convert_ready_entities'] = [ + '#type' => 'radios', + '#title' => 'Transmutation Method', + '#description' => 'Tripal Alchemist can automatically convert all entities from a source bundle to a destination bundle, if those entities already meet the criteria for the destination bundle. This typically means that a type_id column or property is already set. You can instead choose to manually select entities to convert.', + '#options' => ['Automatic', 'Manual'], + '#default_value' => 'Automatic', + '#ajax' => [ + 'callback' => 'tripal_alchemist_destination_bundle_callback', + 'wrapper' => 'report_on_migrations_wrapper', + 'effect' => 'fade' + ], + ]; + + // Create the divs for AJAX rebuilding. One for the destination bundle select, one for the transaction overview $form['div1'] = [ '#type' => 'fieldset', @@ -95,6 +109,7 @@ function tripal_alchemist_converter_form($form, &$form_state) { } + $form['div1']['destination_bundle'] = [ '#type' => 'select', '#title' => t('Destination Bundle'), @@ -105,6 +120,7 @@ function tripal_alchemist_converter_form($form, &$form_state) { '#ajax' => [ 'callback' => 'tripal_alchemist_destination_bundle_callback', 'wrapper' => 'report_on_migrations_wrapper', + 'effect' => 'fade' ], ]; @@ -141,7 +157,7 @@ function tripal_alchemist_converter_form($form, &$form_state) { $form['div2']['submit'] = [ '#type' => 'submit', - '#value' => t('Submit'), + '#value' => t('Transmute (Submit)'), ]; return $form; From e95eb5e5071e19edf5cdbc6274170f492d8ef3d5 Mon Sep 17 00:00:00 2001 From: Vlad Dracula Date: Fri, 19 Jan 2018 17:43:50 -0500 Subject: [PATCH 3/6] form is acceptable. The selected migration is underway in API --- includes/tripal_alchemist.api.inc | 90 ++++++++++++++- includes/tripal_alchemist_converter.form.inc | 109 +++++++++++++++---- 2 files changed, 177 insertions(+), 22 deletions(-) diff --git a/includes/tripal_alchemist.api.inc b/includes/tripal_alchemist.api.inc index 7bd3976..1c65521 100644 --- a/includes/tripal_alchemist.api.inc +++ b/includes/tripal_alchemist.api.inc @@ -159,6 +159,8 @@ function tripal_alchemist_convert_all_entities($args) { //Need to use query builder instead //on conflict will ignore duplicate insert attempts from, say, migrating 2x and resulting in duplicate id's + + //TODO: UPDATE THIS TO MODERN QUERY BUILDER, SEE FORM //copy the entity over from source to destination $sql = "INSERT INTO " . $destination_table . " (entity_id, record_id) (SELECT AB.entity_id AS entity_id, AB.record_id AS record_id FROM " . $chado_base_table . " A @@ -215,6 +217,90 @@ AND AP.value = :descrim_prop_value)"; } +function tripal_alchemist_convert_select_entities($args) { + dpm($args); + + $source_bundle = $args['source_bundle']; + $destination_bundle = $args['destination_bundle']; + $source_entities = $args['source_entities']; + + + if (!$source_bundle || !$destination_bundle) { + tripal_set_message("Error: Destination and source bundle not provided. Cannot convert entities without source and destination bundles.", TRIPAL_ERROR); + } + + + //get all our source and destination table info + $descriminating_type_cvterm_id = $destination_bundle->type_id; + $descriminating_prop_value = $destination_bundle->type_value; + $type_column = $destination_bundle->type_column; + $source_bundle_table = "public.chado_" . $source_bundle->name; + $destination_term = $destination_bundle->term_id; + $destination_table = "public.chado_" . $destination_bundle->name; + $chado_base_table = "chado." . $source_bundle->data_table; + $chado_prop_table = $chado_base_table . "prop"; + + //TODO: add any hard-coded exceptions here since we guess the primary record column + $base_record_column = $source_bundle->data_table . "_id"; + + + //First, set the property in Chado for each selected record. + + foreach ($source_entities as $entity_id) { + $chado_entity_table = chado_get_bundle_entity_table($source_bundle); + $record_id = db_select($chado_entity_table, 'CE') + ->fields('CE', ['record_id']) + ->condition('CE.entity_id', $entity_id) + ->execute() + ->fetchField(); + + if (!$record_id){ tripal_report_error("Could not retrieve record id for entity $entity_id. Aborting.", TRIPAL_ERROR); + } + + $record = ['table' => $source_bundle->data_table, 'id' => $record_id]; + $property = [ + 'type_id' => $descriminating_type_cvterm_id, + 'value' => $descriminating_prop_value, + ]; + $options = ['update_if_present' => TRUE]; + + if (!chado_insert_property($record, $property, $options)) { + tripal_report_error("Could not update property for entity $entity_id. Aborting.", TRIPAL_ERROR); + return; + } + } + + //Now, perform the three-step transmutation... but only on the selected entities + + + //NOTE... THIS WOULD BE A LOT SIMPLER IF I HAD THE ENTITY AND RECORD ID- THATS ALL I NEED! + //I JUST HAD IT IN THE FORM! + //LETS PASS IT IN INSTEAD! + + + //copy the entity over from source to destination + $sql = "INSERT INTO " . $destination_table . " (entity_id, record_id) + (SELECT AB.entity_id AS entity_id, AB.record_id AS record_id FROM " . $chado_base_table . " A + INNER JOIN " . $chado_prop_table . " AP ON A." . db_escape_field($base_record_column) . " = AP. " . ($base_record_column) . " + INNER JOIN chado.cvterm CVT ON AP." . ($type_column) . " = CVT.cvterm_id + INNER JOIN " . $source_bundle_table . " AB ON A." . ($base_record_column) . " = AB.record_id + LEFT JOIN " . $destination_table . " DT ON A." . $base_record_column . " = DT.record_id + WHERE CVT.cvterm_id = :cvterm_id + AND AP.value = :descrim_prop_value + AND DT.record_id IS NULL)"; + + //removed: ON CONFLICT DO NOTHING; for older versions of postgres + + + $results = db_query($sql, [ + ":cvterm_id" => $descriminating_type_cvterm_id, + ":descrim_prop_value" => $descriminating_prop_value, + ]); + + +} + + /** * Given a bundle object, count the number of entries for that bundle. * @@ -245,8 +331,8 @@ function function_tripal_alchemist_get_bundle($bundle_id) { function tripal_alchemist_get_all_entities_from_bundle($bundle) { - $base_table = $bundle->table; - $tb_table = "chado_" . $bundle->name; + $base_table = $bundle->table; + $tb_table = "chado_" . $bundle->name; $query = db_select($tb_table, 'tb'); diff --git a/includes/tripal_alchemist_converter.form.inc b/includes/tripal_alchemist_converter.form.inc index 8bb009e..0fe4abf 100644 --- a/includes/tripal_alchemist_converter.form.inc +++ b/includes/tripal_alchemist_converter.form.inc @@ -39,20 +39,19 @@ function tripal_alchemist_converter_form($form, &$form_state) { ]; - $form['convert_ready_entities'] = [ + $form['transmutation_type'] = [ '#type' => 'radios', '#title' => 'Transmutation Method', '#description' => 'Tripal Alchemist can automatically convert all entities from a source bundle to a destination bundle, if those entities already meet the criteria for the destination bundle. This typically means that a type_id column or property is already set. You can instead choose to manually select entities to convert.', - '#options' => ['Automatic', 'Manual'], + '#options' => ['Automatic' => 'Automatic', 'Manual' => 'Manual'], '#default_value' => 'Automatic', '#ajax' => [ 'callback' => 'tripal_alchemist_destination_bundle_callback', 'wrapper' => 'report_on_migrations_wrapper', - 'effect' => 'fade' + 'effect' => 'fade', ], ]; - // Create the divs for AJAX rebuilding. One for the destination bundle select, one for the transaction overview $form['div1'] = [ '#type' => 'fieldset', @@ -120,7 +119,7 @@ function tripal_alchemist_converter_form($form, &$form_state) { '#ajax' => [ 'callback' => 'tripal_alchemist_destination_bundle_callback', 'wrapper' => 'report_on_migrations_wrapper', - 'effect' => 'fade' + 'effect' => 'fade', ], ]; @@ -136,24 +135,33 @@ function tripal_alchemist_converter_form($form, &$form_state) { $destination_bundle = $all_bundles_array[$selected_destination]; - $table = tripal_alchemist_build_transaction_table($source_bundle, $destination_bundle); + //User can either let alchemist automatically convert entities that have properties already set + // OR user can view list of entities and manually select those that match. + //TODO: third option: filter by a source bundle property/value pair + $transmutation_type = $form_state['values']['transmutation_type']; - if (!$table) { - $form['div2']['kill'] = ['#markup' => '

No qualifying entries. Please pick another source or destination table.

']; + if ($transmutation_type == 'Automatic') { + $table = tripal_alchemist_build_transaction_table($source_bundle, $destination_bundle); - return $form; - } - - $markup = '

Qualifying Entities

Entities from the source bundle that meet the Destination bundle storage criteria are listed below.

ALL of the below entities will be transformed into the destination entity bundle type. Future versions of Tripal Alchemist will allow transforming select entities or overwriting properties.

'; + if (!$table) { + $form['div2']['kill'] = ['#markup' => '

No qualifying entries. Please pick another source or destination table.

']; + return $form; + } + $markup = '

Qualifying Entities

Entities from the source bundle that meet the Destination bundle storage criteria are listed below.

ALL of the below entities will be transformed into the destination entity bundle type. Future versions of Tripal Alchemist will allow transforming select entities or overwriting properties.

'; - $markup .= theme('table', $table); + $markup .= theme('table', $table); - $form['div2']['transaction_summary'] = [ - '#type' => 'markup', - '#markup' => $markup, - ]; + $form['div2']['transaction_summary'] = [ + '#type' => 'markup', + '#markup' => $markup, + ]; + } + //if manual, we're going to do instead build a checkbox table + if ($transmutation_type == 'Manual') { + $form = tripal_alchemist_build_choosable_table($form, $source_bundle); + } $form['div2']['submit'] = [ '#type' => 'submit', @@ -165,11 +173,12 @@ function tripal_alchemist_converter_form($form, &$form_state) { function tripal_alchemist_converter_form_submit($form, &$form_state) { + global $user; $source_bundle_id = $form_state['values']['source_bundle']; $destination_bundle_id = $form_state['values']['destination_bundle']; - + $transmutation_type = $form_state['values']['transmutation_type']; $source_bundle = tripal_load_bundle_entity(['id' => $source_bundle_id]); $destination_bundle = tripal_load_bundle_entity(['id' => $destination_bundle_id]); @@ -179,10 +188,22 @@ function tripal_alchemist_converter_form_submit($form, &$form_state) { "destination_bundle" => $destination_bundle, ]; + // tripal_add_job("Alchemist transmute:" . $source_bundle->label . "to " . $destination_bundle->label, 'tripal_alchemist', 'tripal_alchemist_convert_all_entities', $job_args, $user->uid, 10); - tripal_set_message("Transmutation successful!", TRIPAL_INFO); - tripal_alchemist_convert_all_entities($job_args); + if ($transmutation_type == 'Automatic') { + tripal_alchemist_convert_all_entities($job_args); + tripal_set_message("Transmutation successful!", TRIPAL_INFO); + } + if ($transmutation_type == 'Manual') { + $source_entities = $form_state['values']['manual_entity_select']; + $source_entities = array_filter($source_entities);//remove unchecked selections + dpm($source_entities); + + $job_args['source_entities'] = $source_entities; + tripal_alchemist_convert_select_entities($job_args); + + } } @@ -205,6 +226,7 @@ function tripal_alchemist_destination_bundle_callback($form) { * @return array|null */ function tripal_alchemist_build_transaction_table($source_bundle, $destination_bundle) { + // What we want to do is a) Pull all the **source** bundle entities // and look at how many of those qualify for the destination bundle. $source_table = "chado." . $source_bundle->data_table;//CBT CHADO BASE TABLE @@ -261,3 +283,50 @@ function tripal_alchemist_build_transaction_table($source_bundle, $destination_b return $table; } + +function tripal_alchemist_build_choosable_table($form, $source_bundle) { + + // What we want to do is + // * Pull all the **source** bundle entities + // * Build a checkbox table with each entity + //TODO this would be much better if it was searchable by property or anything really... + + $source_table = "chado." . $source_bundle->data_table;//CBT CHADO BASE TABLE + $source_entity_table = "public.chado_" . $source_bundle->name; //SET SOURCE ENTITY TABLE + + + //TODO: Based on the above values, we need to modify the SQL to select from a type_id column or from a linker table. + //TODO: Joining on the data_table_id is risky. This works for analysis but which ones does it fail on? + //TODO: CBT.name: is this fair? What can I get that's relaiably human readable? + $query = db_select($source_table, 'CBT'); + $query->fields('SET', ['record_id', 'entity_id']); + $query->fields('CBT', ['name']); + $query->innerJoin($source_entity_table, 'SET', 'SET.record_id = CBT.' . $source_bundle->data_table . '_id'); + $results = $query->execute()->fetchAll(); + + $rows = []; + + foreach ($results as $result) { + $rows[$result->entity_id] = [ + $result->record_id, + $result->entity_id, + $result->name, + ]; + } + + if (!$rows) { + return NULL; + } + + $headers = ['Record ID', 'Entity ID', 'Name']; + + $form['div2']['manual_entity_select'] = [ + '#type' => 'tableselect', + '#header' => $headers, + '#options' => $rows, + '#empty' => t('The source bundle is empty'), + ]; + + return ($form); +} + From 66c703964640e5211c2b2b7e90e1319a695a5969 Mon Sep 17 00:00:00 2001 From: Vlad Dracula Date: Fri, 19 Jan 2018 18:18:40 -0500 Subject: [PATCH 4/6] begin using query builder for manual call --- includes/tripal_alchemist.api.inc | 41 ++---- includes/tripal_alchemist_converter.form.inc | 13 +- ...ipal_alchemist_property_converter.form.inc | 138 ------------------ 3 files changed, 24 insertions(+), 168 deletions(-) delete mode 100644 includes/tripal_alchemist_property_converter.form.inc diff --git a/includes/tripal_alchemist.api.inc b/includes/tripal_alchemist.api.inc index 1c65521..8be7b41 100644 --- a/includes/tripal_alchemist.api.inc +++ b/includes/tripal_alchemist.api.inc @@ -218,7 +218,6 @@ AND AP.value = :descrim_prop_value)"; function tripal_alchemist_convert_select_entities($args) { - dpm($args); $source_bundle = $args['source_bundle']; $destination_bundle = $args['destination_bundle']; @@ -228,7 +227,9 @@ function tripal_alchemist_convert_select_entities($args) { if (!$source_bundle || !$destination_bundle) { tripal_set_message("Error: Destination and source bundle not provided. Cannot convert entities without source and destination bundles.", TRIPAL_ERROR); } - + if ( $source_bundle->data_table != $destination_bundle->data_table){ + tripal_set_message("Error: destination and source bundles have the same base table.", TRIPAL_ERROR); + } //get all our source and destination table info $descriminating_type_cvterm_id = $destination_bundle->type_id; @@ -246,6 +247,8 @@ function tripal_alchemist_convert_select_entities($args) { //First, set the property in Chado for each selected record. + $entity_to_record = []; + foreach ($source_entities as $entity_id) { $chado_entity_table = chado_get_bundle_entity_table($source_bundle); $record_id = db_select($chado_entity_table, 'CE') @@ -268,35 +271,23 @@ function tripal_alchemist_convert_select_entities($args) { tripal_report_error("Could not update property for entity $entity_id. Aborting.", TRIPAL_ERROR); return; } - } - //Now, perform the three-step transmutation... but only on the selected entities + //insert into the destination table + //TODO WAIT HOW DOES IT KNOW IF ITS IN CHADO OR PUBLIC? + $result = db_insert($destination_table) + ->fields(['entity_id' => $entity_id, 'record_id' => $record_id]); + //update the tripal entity table - //NOTE... THIS WOULD BE A LOT SIMPLER IF I HAD THE ENTITY AND RECORD ID- THATS ALL I NEED! - //I JUST HAD IT IN THE FORM! - //LETS PASS IT IN INSTEAD! + $result = db_update(""); + //delete from source table - //copy the entity over from source to destination - $sql = "INSERT INTO " . $destination_table . " (entity_id, record_id) - (SELECT AB.entity_id AS entity_id, AB.record_id AS record_id FROM " . $chado_base_table . " A - INNER JOIN " . $chado_prop_table . " AP ON A." . db_escape_field($base_record_column) . " = AP. " . ($base_record_column) . " - INNER JOIN chado.cvterm CVT ON AP." . ($type_column) . " = CVT.cvterm_id - INNER JOIN " . $source_bundle_table . " AB ON A." . ($base_record_column) . " = AB.record_id - LEFT JOIN " . $destination_table . " DT ON A." . $base_record_column . " = DT.record_id - WHERE CVT.cvterm_id = :cvterm_id - AND AP.value = :descrim_prop_value - AND DT.record_id IS NULL)"; - - //removed: ON CONFLICT DO NOTHING; for older versions of postgres - - - $results = db_query($sql, [ - ":cvterm_id" => $descriminating_type_cvterm_id, - ":descrim_prop_value" => $descriminating_prop_value, - ]); + $result = db_delete($source_bundle_table) + ->fields(['entity_id' => $entity_id, 'record_id' => $record_id]); + //TODO: ONLY DELETE IF ITS PRESENT IN THE DESTINATION + } } diff --git a/includes/tripal_alchemist_converter.form.inc b/includes/tripal_alchemist_converter.form.inc index 0fe4abf..bd09d9b 100644 --- a/includes/tripal_alchemist_converter.form.inc +++ b/includes/tripal_alchemist_converter.form.inc @@ -198,7 +198,6 @@ function tripal_alchemist_converter_form_submit($form, &$form_state) { if ($transmutation_type == 'Manual') { $source_entities = $form_state['values']['manual_entity_select']; $source_entities = array_filter($source_entities);//remove unchecked selections - dpm($source_entities); $job_args['source_entities'] = $source_entities; tripal_alchemist_convert_select_entities($job_args); @@ -308,9 +307,9 @@ function tripal_alchemist_build_choosable_table($form, $source_bundle) { foreach ($results as $result) { $rows[$result->entity_id] = [ - $result->record_id, - $result->entity_id, - $result->name, + 'record_id' => $result->record_id, + 'entity_id' => $result->entity_id, + 'name' => $result->name, ]; } @@ -318,7 +317,11 @@ function tripal_alchemist_build_choosable_table($form, $source_bundle) { return NULL; } - $headers = ['Record ID', 'Entity ID', 'Name']; + $headers = [ + 'record_id' => t('Record ID'), + 'entity_id' => t('Entity ID'), + 'name' => t('Name'), + ]; $form['div2']['manual_entity_select'] = [ '#type' => 'tableselect', diff --git a/includes/tripal_alchemist_property_converter.form.inc b/includes/tripal_alchemist_property_converter.form.inc deleted file mode 100644 index 18bd7d4..0000000 --- a/includes/tripal_alchemist_property_converter.form.inc +++ /dev/null @@ -1,138 +0,0 @@ - '

Welcome to Tripal Alchemist property converter. - -This form will allow you to modify the properties of selected analyses so that they will be elligible to be transformed to new content types. -

Content types that share a chado table have a type, either via a property linker table or a type_id column. This tool will allow you to change existing entries to match a new type, so that they can be converted.

-

Full documentation of this module is available on the projects Github page.

- ', - ]; - - - //Fetch all bundles - - $all_bundles_object = tripal_alchemist_get_all_bundles(); - - $all_bundles_array = []; - $bundle_options = []; - - foreach ($all_bundles_object as $bundle) { - //Do I really need to do this? - if ($bundle->type != 'TripalEntity') { - continue; - } - $bundle_options[$bundle->id] = $bundle->label; - $all_bundles_array[$bundle->id] = $bundle; - } - - - - $form['source_bundle'] = [ - '#type' => 'select', - '#title' => t('Source Bundle'), - '#description' => t('The source bundle, which contains the entities you would like to transform.'), - '#empty_option' => t('- Select -'), - '#options' => $bundle_options, - '#default_value' => NULL, - '#ajax' => [ - 'callback' => 'tripal_alchemist_source_bundle_callback', - 'wrapper' => 'destination_bundle_wrapper', - 'effect' => 'fade', - ], - ]; - - - //create the divs for AJAX rebuilding. One for the destination bundle select, one for the transaction overview - $form['div1'] = [ - '#type' => 'fieldset', - '#collapsible' => FALSE, - '#prefix' => '
', - '#suffix' => '
', - ]; - - - $source_bundle = "analysis"; - - $source_options = tripal_alchemist_get_all_entities_from_bundle($source_bundle); - - - $selected_base_table = isset($form_state['values']['source_bundle']) ? $form_state['values']['source_bundle'] : NULL; - - if (!$selected_base_table) { - $form['div1']['instructions_no_select'] = [ - '#markup' => '

Destination Bundle

First, select a Source Bundle above. You will then be able to choose a destination bundle from al bundles sharing a base table.

', - ]; - return $form; - } - - $source_bundle = $all_bundles_array[$selected_base_table]; - $source_table = $source_bundle->data_table; - - //How many records here? - - $source_count = tripal_alchemist_fetch_current_bundle_entities($source_bundle); - - - if (!$source_count) { - $form['div1']['feedback'] = [ - '#markup' => "

Your selected source bundle $source_bundle->label has no entities in the database. You must populate the source bundle first, either by creating content or migrating Tripal 2 nodes.

", - ]; - } - $form['div1']['feedback'] = [ - '#markup' => "

There are $source_count records in the $source_bundle->label bundle.

", - ]; - - - //Create dropdown list of bundles for source that match that table - - $matching_destination_bundles = tripal_alchemist_get_matching_bundles($source_table); - unset($matching_destination_bundles[$selected_base_table]);//remove the source bundle - - if (count($matching_destination_bundles) == 0) { - $form['div1']['instructions_no_matches'] = [ - '#markup' => "

Your selected source bundle is the only bundle using the base table $source_table.

Please select a different source bundle, or define a new bundle with the same base table to serve as your destination bundle.

", - ]; - return $form; - } - - $form['div1']['destination_bundle'] = [ - '#type' => 'select', - '#title' => t('Destination Bundle'), - '#description' => t('Destination bundle. Your selected entities will be converted to Tripal Entities of this bundle type.'), - '#default' => NULL, - '#empty_option' => t('- Select -'), - '#options' => $matching_destination_bundles, - '#ajax' => [ - 'callback' => 'tripal_alchemist_properties_destination_bundle_callback', - 'wrapper' => 'report_on_migrations_wrapper', - ], - ]; - - - $selected_destination = isset($form_state['values']['destination_bundle']) ? $form_state['values']['destination_bundle'] : NULL; - - $destination_bundle = $all_bundles_array[$selected_destination]; - - - $source_options = tripal_alchemist_get_all_entities_from_bundle($source_bundle); - - $header = ['entity_id', 'name']; - - $form['div2']['select_entities_to_convert'] = [ - '#type' => 'tableselect', - '#header' => $header, - '#options' => $options, - '#multiple' => TRUE - - ]; - - return($form); -} - - -function tripal_alchemist_properties_destination_bundle_callback($form) { - return $form['div1']; -} \ No newline at end of file From 7edc750e87cd3214d7d1578d67ac1324f4c96418 Mon Sep 17 00:00:00 2001 From: Vlad Dracula Date: Fri, 19 Jan 2018 19:18:57 -0500 Subject: [PATCH 5/6] manual transmutation works perhaps recklessly --- includes/tripal_alchemist.api.inc | 35 +++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/includes/tripal_alchemist.api.inc b/includes/tripal_alchemist.api.inc index 8be7b41..d28b575 100644 --- a/includes/tripal_alchemist.api.inc +++ b/includes/tripal_alchemist.api.inc @@ -227,7 +227,7 @@ function tripal_alchemist_convert_select_entities($args) { if (!$source_bundle || !$destination_bundle) { tripal_set_message("Error: Destination and source bundle not provided. Cannot convert entities without source and destination bundles.", TRIPAL_ERROR); } - if ( $source_bundle->data_table != $destination_bundle->data_table){ + if ($source_bundle->data_table != $destination_bundle->data_table) { tripal_set_message("Error: destination and source bundles have the same base table.", TRIPAL_ERROR); } @@ -257,7 +257,8 @@ function tripal_alchemist_convert_select_entities($args) { ->execute() ->fetchField(); - if (!$record_id){ tripal_report_error("Could not retrieve record id for entity $entity_id. Aborting.", TRIPAL_ERROR); + if (!$record_id) { + tripal_report_error("Could not retrieve record id for entity $entity_id. Aborting.", TRIPAL_ERROR); } $record = ['table' => $source_bundle->data_table, 'id' => $record_id]; @@ -265,6 +266,8 @@ function tripal_alchemist_convert_select_entities($args) { 'type_id' => $descriminating_type_cvterm_id, 'value' => $descriminating_prop_value, ]; + + dpm($property); $options = ['update_if_present' => TRUE]; if (!chado_insert_property($record, $property, $options)) { @@ -273,20 +276,30 @@ function tripal_alchemist_convert_select_entities($args) { } //insert into the destination table - //TODO WAIT HOW DOES IT KNOW IF ITS IN CHADO OR PUBLIC? - $result = db_insert($destination_table) - ->fields(['entity_id' => $entity_id, 'record_id' => $record_id]); + //Ignore duplicates + try { + $result = db_insert($destination_table) + ->fields(['entity_id' => $entity_id, 'record_id' => $record_id]) + ->execute(); } catch (Exception $e) { + // ignored + } //update the tripal entity table - $result = db_update(""); - - //delete from source table + $result = db_update("public.tripal_entity") + ->fields([ + 'bundle' => $destination_bundle->name, + 'term_id' => $destination_term, + ]) + ->condition('id', $entity_id, '=') + ->execute(); + //delete from source + //TODO: CHECK THAT IT WAS SUCCESFUL BEFORE DELETING $result = db_delete($source_bundle_table) - ->fields(['entity_id' => $entity_id, 'record_id' => $record_id]); - //TODO: ONLY DELETE IF ITS PRESENT IN THE DESTINATION - + ->condition('entity_id', $entity_id) + ->condition('record_id' , $record_id) + ->execute(); } } From 548088fcc1205b6c0c50688b2b69ae8f08b6d483 Mon Sep 17 00:00:00 2001 From: Vlad Dracula Date: Fri, 19 Jan 2018 19:20:28 -0500 Subject: [PATCH 6/6] remove unncessary form --- tripal_alchemist.module | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tripal_alchemist.module b/tripal_alchemist.module index f7b2da0..9d25d74 100644 --- a/tripal_alchemist.module +++ b/tripal_alchemist.module @@ -29,16 +29,6 @@ function tripal_alchemist_menu() { 'file_path' => drupal_get_path('module', 'tripal_alchemist'), ]; - $items[$admin_url_base . "/property_converter"] = [ - 'title' => 'Tripal Alchemist Property Converter', - 'description' => t('Prepare your entities for conversion by altering their properties.'), - 'access arguments' => [' tripal alchemist'], - 'page callback' => 'drupal_get_form', - 'page arguments' => ['tripal_alchemist_property_converter_form'], - 'file' => 'includes/tripal_alchemist_property_converter.form.inc', - 'file_path' => drupal_get_path('module', 'tripal_alchemist'), - ]; - return $items; }