From 883767345d5d89c9bfdae6599a1c0d32d5bc7756 Mon Sep 17 00:00:00 2001 From: Stephen Ficklin Date: Tue, 20 Feb 2024 13:39:38 -0800 Subject: [PATCH 1/5] first commit of importers doc --- docs/dev_guide/biodata.rst | 1 + docs/dev_guide/biodata/chado.rst | 2 +- docs/dev_guide/biodata/importers.rst | 551 +++++++++++++++++++++++++++ 3 files changed, 553 insertions(+), 1 deletion(-) create mode 100644 docs/dev_guide/biodata/importers.rst diff --git a/docs/dev_guide/biodata.rst b/docs/dev_guide/biodata.rst index 3543b98..9ca2f83 100644 --- a/docs/dev_guide/biodata.rst +++ b/docs/dev_guide/biodata.rst @@ -15,3 +15,4 @@ That said, there are still situations in which you may want to support additiona biodata/tripaldbx biodata/chado biodata/bulkPgSchemaInstall + biodata/importers diff --git a/docs/dev_guide/biodata/chado.rst b/docs/dev_guide/biodata/chado.rst index c9456ee..19b7245 100644 --- a/docs/dev_guide/biodata/chado.rst +++ b/docs/dev_guide/biodata/chado.rst @@ -1,6 +1,6 @@ GMOD Chado Schema Integration -================================= +============================= .. _GMOD: http://gmod.org/wiki/Main_Page diff --git a/docs/dev_guide/biodata/importers.rst b/docs/dev_guide/biodata/importers.rst new file mode 100644 index 0000000..cd456ba --- /dev/null +++ b/docs/dev_guide/biodata/importers.rst @@ -0,0 +1,551 @@ +Creating a Chado Data Importer +============================== +Often we want to simplify import of data into Chado by provide a user interface by which a site developer can easily select a file, provide values for a few settings and click a button to load a file. Examples of existing loaders compatible with Tripal include the FASTA and GFF loaders that come with the Tripal Genome module. These loaders allow users to import data into Chado that are in FASTA or GFF format. If you would like to support loading of a file type you can create a new loader by implementing your own ``TripalImporter`` plugin and writing the code to insert or update the data into Chado. The ``TripalImporter`` plugin provides many conveniences. For example, it provides an input form that automatically handles files uploads, it performs job submission, logging, and provides progress updates during execution. Adding a ``TripalImporter`` to your module allows means anyone who installs your module can use your new loader! + +To document how to create a new importer, we will describe use of the ``TripalImporter`` class within the context of a new simple importer called the ``ExampleImporter``. This importer will read in a comma-separated file containing genomic features and their properties (a fictional "Test Format" file). The loader will split each line into feature and property values, and then insert each property into the ``featureprop`` table of Chado using a controlled vocabulary term (supplied by the user) as the ``type_id`` for the property. + +.. note:: + Prior to starting your data loader you should plan how the data will be imported into Chado. Chado is a flexible database schema and it may be challenging at times to decide in to which tables data should be placed. It is recommended to reach out to the Chado community to solicit advice. Doing so will allow you to share your loader will other Tripal users more easily! + +Create a Custom Module +---------------------- +To create your own importer, you first need to have a custom extension module in which the loader will be provided. If you do not know how to create a module, see the section titled :doc:`../module_dev` for further direction. For this document we will describe creation of a new importer in a fake module named ``tripal_example_importer``. + +Create the Plugin File +---------------------- +To define a new class that extends ``TripalImporter``, you should create a new class file in the ``src/Plugin/TripalImporter/`` directory of your module. You may need to create the ``src/Plugin/TripalImporter`` directory. For the example described here, we will create a new ``TripalImporter`` plugin named ``ExampleImporter``. We must name the file the same as the class (with a .php extension) and place the file here: ``tripal_example_importer\src\Plugin\TripalImporter\ExampleImporter.inc``. + +The Tripal Chado module provides a base class named ``ChadoImporterBase`` that all importers for Chado should use. Initally our importer plugin class is as follows: + +.. code-block:: php + + Tripal -> Data Loaders``. + +.. note:: + + If after creation of your importer file, Tripal does not show a link for it in the Data Loaders page, check that you have named your class file correctly and it is in the path described above. Sometimes a clear cache is necessary (``drush cc all``). + + +Static Variables +----------------- +The next step in creation of your importer is setting the static member variables. Open the ``TripalImporter`` class file that comes with Tripal and found here ``tripal/includes/TripalImporter.inc``. Copy the ``public static`` member variables at the top of the class into your own class. For your importer, override any of the ``public static`` variables that need to be different from the default. + +.. note:: + + For the sake of simplicity in this document, many of the default settings are not changed, and therefore, not all are included. + +Our ``ExampleImporter`` class now appears as follows: + +.. code-block:: php + + + /** + * @see TripalImporter + */ + class ExampleImporter extends TripalImporter { + + /** + * The name of this loader. This name will be presented to the site + * user. + */ + public static $name = 'Example TST File Importer'; + + /** + * The machine name for this loader. This name will be used to construct + * the URL for the loader. + */ + public static $machine_name = 'tripal_tst_loader'; + + /** + * A brief description for this loader. This description will be + * presented to the site user. + */ + public static $description = 'Loads TST files'; + + /** + * An array containing the extensions of allowed file types. + */ + public static $file_types = ['txt', 'tst', 'csv']; + + /** + * Provides information to the user about the file upload. Typically this + * may include a description of the file types allowed. + */ + public static $upload_description = 'TST is a fictional format. Its a 2-column, CSV file. The columns should be of the form featurename, and text'; + + /** + * Indicates the methods that the file uploader will support. + */ + public static $methods = [ + // Allow the user to upload a file to the server. + 'file_upload' => TRUE, + // Allow the user to provide the path on the Tripal server for the file. + 'file_local' => TRUE, + // Allow the user to provide a remote URL for the file. + 'file_remote' => TRUE, + ]; + } + +.. warning:: + + The variables that are ``private static`` **should not** be copied and should not be changed. Only copy and change the ``public static`` member variables. + + +Now that we've given our importer a name and description, it will show up at ``/admin/tripal/loaders``: + +.. image:: ./custom_data_loader.0.png + + +Form Components +----------------- + +By default, the ``TripalImporter`` class will provide the necessary upload widgets to allow a user to upload files for import. The static variables we set in the previous step dictate how that uploader appears to the user. However, for this example, our importer needs additional information from the user before data can be loaded. We need to provide additional form widgets. + +Typically, to create forms, Drupal provides form hooks: ``form``, ``form_validate``, ``form_submit``. The **TripalImporter** wraps these for us as class functions named ``form``, ``formValidate`` and ``formSubmit``. We can override these class functions to provide additional widgets to the form. + +.. note:: + + Typically we only need to implement the ``form`` and ``formValidate`` functions. The ``formSubmit`` does not need to be modified. + +.. note:: + + If you are not familiar with form creation in Drupal you may want to find a Drupal reference book that provides step-by-step instructions. Additionally, you can explore the `API documentation for form construction for Drupal 7 `_. Here, this example expects you are comfortable with form construction in Drupal. + + +The form function +^^^^^^^^^^^^^^^^^ +To provide custom widgets for our importer we need to implement the ``form`` function. However, let's review the current form provided by the TripalImporter for us already. Using the static variables settings specified above the form automatically provides a **File Upload** field set, and an **Analysis** selector. The **File Upload** area lets users choose to upload a file, provide a **Server path** to a file already on the web server or a **Remote path** for files located via a downloadable link on the web. The **Analysis** selector is important because it allows the user to specify an analysis that describes how the data file was created. + +.. image:: ./custom_data_loader.1.oob_file_interface.png + +.. image:: ./custom_data_loader.2.oob_analysis_select.png + +For our example TST file importer these upload options are sufficient. However, for our data import we want the user provide a CV term. We want our importer to read the file, split it into feature and values, and insert properties into the ``featureprop`` table of Chado using the the CV term as the ``type_id`` for the table. + +To add a widget that allows the user to provide a CV term, we must implement the ``form`` function and include code using Drupal's Form API that will add the widget. + +.. code-block:: php + :name: ExampleImporter::form + + + public function form($form, &$form_state) { + + + // For our example loader let's assume that there is a small list of + // vocabulary terms that are appropriate as properties for the genomics + // features. Therefore, we will provide an array of sequence ontology terms + // the user can select from. + $terms = [ + ['id' => 'SO:0000235'], + ['id' => 'SO:0000238'], + ['id' => 'SO:0000248'] + ]; + + // Construct the options for the select drop down. + $options = []; + // Iterate through the terms array and get the term id and name using + // appropriate Tripal API functions. + foreach ($terms as $term){ + $term_object = chado_get_cvterm($term); + $id = $term_object->cvterm_id; + $options[$id] = $term_object->name; + } + + // Provide the Drupal Form API array for a select box. + $form['pick_cvterm'] = [ + '#title' => 'CVterm', + '#description' => 'Please pick a CVterm. The loaded TST file will associate the values with this term as a feature property.', + '#type' => 'select', + '#default_value' => '0', + '#options' => $options, + '#empty_option' => '--please select an option--' + ]; + + // The form function must always return our form array. + return $form; + } + +Our form now has a select box! + +.. image:: ./custom_data_loader.3.cvterm_select.png + + +Using AJAX in forms +""""""""""""""""""" + +.. note:: + + This section is not yet available. For now, check out the Drupal AJAX guide https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax/7.x + + +The formValidate function +^^^^^^^^^^^^^^^^^^^^^^^^^ +The ``formValidate`` function is responsible for verifying that the user supplied values from the form submission are valid. To warn the user of inappropriate values, the Drupal API function, ``form_set_error()`` is used. It provides an error message, highlights in red the widget containing the bad value, and prevents the form from being submitted--allowing the user to make corrections. In our example code, we will check that the user selected a CV term from the ``pick_cvterm`` widget. + + +.. code-block:: php + + public function formValidate($form, &$form_state) { + + // Always call the TripalImporter (i.e. parent) formValidate as it provides + // some important feature needed to make the form work properly. + parent::formValidate($form, $form_state); + + // Get the chosen CV term form the form state and if there is no value + // set warn the user. + $chosen_cvterm = $form_state['values']['pick_cvterm']; + if ($chosen_cvterm == 0) { + form_set_error('pick_cvterm', 'Please choose a CVterm.'); + } + } + +The implementation above looks for the ``pick_cvterm`` element of the ``$form_state`` and ensures the user selected something. This is a simple example. An implementation for a more complex loader with a variety of widgets will require more validation checks. + +.. note:: + + If our importer followed best practices, it would not need a validator at all. The cvterm select box in the form could be defined as below. Note the ``'#required' => True`` line: this would handle the validation for us. For this tutorial, however, we implement the validation ourselves to demonstrate the function. + + .. code-block:: php + + // Provide the Drupal Form API array for a select box. + $form['pick_cvterm'] = [ + '#title' => 'CVterm', + '#description' => 'Please pick a CVterm. The loaded TST file will associate the values with this term as a feature property.', + '#type' => 'select', + '#default_value' => '0', + '#options' => $options, + '#empty_option' => '--please select an option--' + '#required' => True + ]; + + +When an importer form is submitted and passes all validation checks, a job is automatically added to the **Tripal Job** system. The ``TripalImporter`` parent class does this for us! The **Tripal Job** system is meant to allow long-running jobs to execute behind-the-scenes on a regular time schedule. As jobs are added they are executed in order. Therefore, if a user submits a job using the importer's form then the **Tripal Job** system will automatically run the job the next time it is scheduled to run or it can be launched manually by the site administrator. + + +Importer Execution +------------------ +The ``form`` and ``formValidate`` functions allow our Importer to receive an input file and additional values needed for import of the data. To execute loading a file the ``TripalImporter`` provides several additional overridable functions: ``run``, ``preRun`` and ``postRun``. When the importer is executed, the ``preRun`` function is called first. It allows the importer to perform setup prior to full execution. The ``run`` function is where the full execution occurs and the ``postRun`` function is used to perform "cleanup" prior to completion. For our ``ExampleImporter`` class we only need to implement the ``run`` function. We have no need to perform any setup or cleanup outside of the typical run. + +The run function +^^^^^^^^^^^^^^^^ +The ``run`` function is called automatically when Tripal runs the importer. For our ``ExampleImporter``, the run function should collect the values provided by the user, read and parse the input file and load the data into Chado. The first step, is to retrieve the user provided values and file details. The inline comments in the code below provide instructions for retrieving these details. + + +.. code-block:: php + + /** + * @see TripalImporter::run() + */ + public function run() { + + // All values provided by the user in the Importer's form widgets are + // made available to us here by the Class' arguments member variable. + $arguments = $this->arguments['run_args']; + + // The path to the uploaded file is always made available using the + // 'files' argument. The importer can support multiple files, therefore + // this is an array of files, where each has a 'file_path' key specifying + // where the file is located on the server. + $file_path = $this->arguments['files'][0]['file_path']; + + // The analysis that the data being imported is associated with is always + // provided as an argument. + $analysis_id = $arguments['analysis_id']; + + // Any of the widgets on our form are also available as an argument. + $cvterm_id = $arguments['pick_cvterm']; + + // Now that we have our file path, analysis_id and CV term we can load + // the file. We'll do so by creating a new function in our class + // called "loadMyFile" and pass these arguments to it. + $this->loadMyFile($analysis_id, $file_path, $cvterm_id); + } + +.. note:: + + We do not need to validate in the ``run`` function that all of the necessary values in the arguments array are valid. Remember, this was done by the ``formValidate`` function when the user submitted the form. Therefore, we can trust that all of the necessary values we need for the import are correct. That is of course provided our ``formValidate`` function sufficiently checks the user input. + +Importing the File +^^^^^^^^^^^^^^^^^^ +To keep the ``run`` function small, we will implement a new function named ``loadMyFile`` that will perform parsing and import of the file into Chado. As seen in the code above, the ``loadMyFile`` function is called in the ``run`` function. + +Initially, lets get a feel for how the importer will work. Lets just print out the values provided to our importer: + + +.. code-block:: php + + public function loadMyFile($analysis_id, $file_path, $cvterm){ + var_dump(["this is running!", $analysis_id, $file_path, $cvterm]); + } + +To test our importer navigate to ``admin > Tripal > Data Importers`` and click the link for our TFT importer. Fill out the form and press submit. If there are no validation errors, we'll receive notice that our job was submitted and given a command to execute the job manually. For example: + +.. + + drush trp-run-jobs --username=admin --root=/var/www/html + + +If we execute our importer we should see the following output: + + +.. code-block:: bash + + Calling: tripal_run_importer(146) + + Running 'Example TST File Importer' importer + NOTE: Loading of file is performed using a database transaction. + If it fails or is terminated prematurely then all insertions and + updates are rolled back and will not be found in the database + + array(4) { + [0]=> + string(16) "This is running!" + [1]=> + string(3) "147" + [2]=> + string(3) "695" + [3]=> + string(72) "/Users/chet/UTK/tripal/sites/default/files/tripal/users/1/expression.tsv" + } + + Done. + + Remapping Chado Controlled vocabularies to Tripal Terms... + + +As you can see, running the job executes our run script, and we have all the variables we need to load the data. All we need to do now is write the code! + +To import data into Chado we will use the Tripal API. After splitting each line of the input file into a genomic feature and its property, we will use the ``chado_select_record`` to match the feature's name with a record in the ``feature`` table of Chado, and the ``chado_insert_property`` to add the property value. + + +.. code-block:: php + + public function loadMyFile($analysis_id, $file_path, $cvterm_id){ + + // We want to provide a progress report to the end-user so that they: + // 1) Recognize that the loader is not hung if running a large file, but is + // executing + // 2) Provides some indication for how long the file will take to load. + // + // Here we'll get the size of the file and tell the TripalImporter how + // many "items" we have to process (in this case bytes of the file). + $filesize = filesize($file_path); + $this->setTotalItems($filesize); + $this->setItemsHandled(0); + + // Loop through each line of file. We use the fgets function so as not + // to load the entire file into memory but rather to iterate over each + // line separately. + $bytes_read = 0; + $in_fh = fopen($file_path, "r"); + while ($line = fgets($in_fh)) { + + // Calculate how many bytes we have read from the file and let the + // importer know how many have been processed so it can provide a + // progress indicator. + $bytes_read += drupal_strlen($line); + $this->setItemsHandled($bytes_read); + + // Remove any trailing white-space from the line. + $line = trim($line); + + // Split line on a comma into an array. The feature name appears in the + // first "column" of data and the property in the second. + $cols = explode(",", $line); + $feature_name = $cols[0]; + $this_value = $cols[1]; + + // Our file has a header with the name 'Feature name' expected as the + // title for the first column. If we see this ignore it. + if ($feature_name == 'Feature name'){ + continue; + } + + // Using the name of the feature from the file, see if we can find a + // record in the feature table of Chado that matches. Note: in reality + // the feature table of Chado has a unique constraint on the uniquename, + // organism_id and type_id columns of the feature table. So, to ensure + // we find a single record ideally we should include the organism_id and + // type_id in our filter and that would require more widgets on our form! + // For simplicity, we will just search on the uniquename and hope we + // find unique features. + $match = ['uniquename' => $feature_name]; + $results = chado_select_record('feature', ['feature_id'], $match); + + // The chado_select_record function always returns an array of matches. If + // we found no matches then this feature doesn't exist and we'll skip + // this line of the file. But, log this issue so the user knows about it. + if (count($results) == 0) { + $this->logMessage('The feature, !feature, does not exist in the database', + ['!feature' => $feature_name], TRIPAL_WARNING); + continue; + } + + // If we failed to find a unique feature then we should warn the user + // but keep on going. + if (count($results) == 0) { + $this->logMessage('The feature, !feature, exists multiple times. ' . + 'Cannot add a property', ['!feature' => $feature_name], TRIPAL_WARNING); + continue; + } + + // If we've made it this far then we have a feature and we can do the + // insert. + $feature = $results[0]; + $record = [ + 'table' => 'feature', + 'id' => $feature->feature_id + ]; + $property = [ + 'type_id' => $cvterm_id, + 'value' => $this_value, + ]; + $options = ['update_if_present' => TRUE]; + chado_insert_property($record, $property, $options); + } + } + +Logging and Progress +-------------------- +During execution of our importer it is often useful to inform the user of progress, status and issues encountered. There are several functions to assist with this. These include the ``logMessage``, ``setTotalItems`` and ``setItemsHandled`` functions. All three of these functions were used in the sample code above of the ``loadMyFile`` function. Here, we provide a bit more detail. + +The logMessage function +^^^^^^^^^^^^^^^^^^^^^^^ +The ``logMessage`` function is meant to allow the importer to provide status messages to the user while the importer is running. The function takes three arguments: + +1) a message string. +2) an array of substitution values. +3) a message status. + +The message string contains the message for the user. You will notice that no variables are included in the string but rather tokens are used as placeholders for variables. This is a security feature provided by Drupal. Consider these lines from the code above: + +.. code-block:: php + + $this->logMessage('The feature, !feature, does not exist in the database', + ['!feature' => $feature_name], TRIPAL_WARNING); + +Notice that ``!feature`` is used in the message string as a placeholder for the feature name. The mapping of ``!feature`` to the actually feature name is provided in the array provided as the second argument. The third argument supports several message types including ``TRIPAL_NOTICE``, ``TRIPAL_WARNING`` and ``TRIPAL_ERROR``. The message status indicates a severity level for the message. By default if no message type is provided the message is of type ``TRIPAL_NOTICE``. + +Any time the ``logMessage`` function is used the message is stored in the job log, and a site admin can review these logs by clicking on the job in the ``admin > Tripal > Tripal Jobs`` page. + +.. note:: + + You should avoid using ``print`` or ``print_r`` statements in a loader to provide messages to the end-user while loading the file. Always use the ``logMessage`` function to ensure all messages are sent to the job's log. + +The setTotalItems and setItemsHandled functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The ``TripalImporter`` class is capable of providing progress updates to the end-user while the importer job is running. This is useful as it gives the end-user a sense for how long the job will take. As shown in the sample code above for the ``loadMyFile`` function, The first step is to tell the ``TripalImporter`` how many items need processing. An **item** is an arbitrary term indicating some measure of countable "units" that will be processed by our importer. + +In the code above we consider a byte as an item, and when all bytes from a file are read we are done loading that file. Therefore the ``setTotalItems`` function is used to tell the importer how many bytes we need to process. As we read each line, we count the number of bytes read and provide that number to the ``setItemsHandled`` function. The ``TripalImporter`` class will automatically calculate progress and print a message to the end-user indicating the percent complete, and some additional details such as the total amount of memory consumed during the loading. + +.. note:: + + All importers are different and the "item" need not be the number of bytes in the file. However, if you want to provide progress reports you must identify an "item" and the total number of items there are for processing. + +Testing Importers +------------------ +Unit Testing is a critically important component of any software project. You should always strive to write tests for your software. Tripal provides unit testing using the ``phpunit`` testing framework. The Tripal Test Suite provides a strategy for adding tests for your new Importer. It will automatically set up and bootstrap Drupal and Tripal for your testing environment, as well as provide database transactions for your tests, and factories to quickly generate data. We will use the Tripal Test Suite to provide unit testing for our ``ExampleImporter``. + +.. note:: + Before continuing, please install and configure Tripal Test Suite. + + For instructions on how to install, configure, and run Tripal Test Suite, `please see the Tripal Test Suite documentation. `_ + + +Example file +^^^^^^^^^^^^ +When developing tests, consider including a small example file as this is good practice both to ensure that your loader works as intended, and for new developers to easily see the expected file format. For our ``ExampleImporter``, we'll include the following sample file and store it in this directory of our module: ``tests/data/example.txt``. + +.. csv-table:: Example input file + :header: "Feature name", "CVterm value" + + "test_gene_1", "blue" + "test_gene_2", "red" + + +Loading the Importer +^^^^^^^^^^^^^^^^^^^^ +Testing your loader requires a few setup steps. First, TripalImporters are not explicitly loaded in your module (note that we never use ``include_once()`` or ``require_once`` in the ``.module`` file). Normally Tripal finds the importer automatically, but for unit testing we must include it to our test class explicitly. Second, we must initialize an instance of our importer class. Afterwards we can perform any tests to ensure our loader executed properly. The following function provides an example for setup of the loader for testing: + +.. code-block:: php + + private function run_loader(){ + + // Load our importer into scope. + module_load_include('inc', 'tripal_example_importer', 'includes/TripalImporter/ExampleImporter'); + + // Create an array of arguments we'll use for testing our importer. + $run_args = [ + 'analysis_id' => $some_analysis_id, + 'cvterm' => $some_cvterm_id + ]; + $file = ['file_local' => __DIR__ . '/../data/exampleFile.txt']; + + // Create a new instance of our importer. + $importer = new \ExampleImporter(); + $importer->create($run_args, $file); + + // Before we run our loader we must let the TripalImporter prepare the + // files for us. + $importer->prepareFiles(); + $importer->run(); + } + +.. note:: + + We highly recommend you make use of database transactions in your tests, especially when running loaders. Simply add ``use DBTransaction;`` at the start of your test class. Please see the `Tripal Test Suite documentation for more information `_. \ No newline at end of file From 3f1ece1a531b5b02d4acff0780ada335c8d9217c Mon Sep 17 00:00:00 2001 From: Stephen Ficklin Date: Thu, 22 Feb 2024 17:25:36 -0800 Subject: [PATCH 2/5] Continued edits --- .../biodata/custom_data_loader.0.png | Bin 0 -> 61349 bytes .../biodata/custom_data_loader.1.png | Bin 0 -> 68520 bytes docs/dev_guide/biodata/importers.rst | 218 ++++++++++-------- 3 files changed, 118 insertions(+), 100 deletions(-) create mode 100644 docs/dev_guide/biodata/custom_data_loader.0.png create mode 100644 docs/dev_guide/biodata/custom_data_loader.1.png diff --git a/docs/dev_guide/biodata/custom_data_loader.0.png b/docs/dev_guide/biodata/custom_data_loader.0.png new file mode 100644 index 0000000000000000000000000000000000000000..8bc4399d4405bc082987332adbfa77ed156a9f0c GIT binary patch literal 61349 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

7+o6Bu=8@V?A)QP)M-jUGPqBKYuFK9?^crxzKd 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 aRQ+k6p_&%f5YzP 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
w+g-U^5uNdTr?^e&qm9ScDki=B)Jv?M!F4t~E>S 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 literal 0 HcmV?d00001 diff --git a/docs/dev_guide/biodata/importers.rst b/docs/dev_guide/biodata/importers.rst index cd456ba..9f0000f 100644 --- a/docs/dev_guide/biodata/importers.rst +++ b/docs/dev_guide/biodata/importers.rst @@ -7,15 +7,35 @@ To document how to create a new importer, we will describe use of the ``TripalIm .. note:: Prior to starting your data loader you should plan how the data will be imported into Chado. Chado is a flexible database schema and it may be challenging at times to decide in to which tables data should be placed. It is recommended to reach out to the Chado community to solicit advice. Doing so will allow you to share your loader will other Tripal users more easily! + +About Drupal Plugins +-------------------- +The Tripal importers use the `Drupal Plugin API `_. The plugin infrastructure of Drupal allows a module to provide new functtionality the builds off of a common interface (such as Tripal's importer interface). + + Create a Custom Module ---------------------- To create your own importer, you first need to have a custom extension module in which the loader will be provided. If you do not know how to create a module, see the section titled :doc:`../module_dev` for further direction. For this document we will describe creation of a new importer in a fake module named ``tripal_example_importer``. + + Create the Plugin File ---------------------- -To define a new class that extends ``TripalImporter``, you should create a new class file in the ``src/Plugin/TripalImporter/`` directory of your module. You may need to create the ``src/Plugin/TripalImporter`` directory. For the example described here, we will create a new ``TripalImporter`` plugin named ``ExampleImporter``. We must name the file the same as the class (with a .php extension) and place the file here: ``tripal_example_importer\src\Plugin\TripalImporter\ExampleImporter.inc``. -The Tripal Chado module provides a base class named ``ChadoImporterBase`` that all importers for Chado should use. Initally our importer plugin class is as follows: +To define a new class that extends ``TripalImporter``, you should create the directory ``src/Plugin/TripalImporter/`` in your module. For the example here, we will create a new ``TripalImporter`` plugin named ``ExampleImporter``. We must name the file the same as the class (with a .php extension) and place the file in the ``TripalImporter`` directory we just created: ``tripal_example_importer\src\Plugin\TripalImporter\ExampleImporter.inc``. Placing the importer class file in the ``src/Plugin/TripalImporter`` directory is all you need for Tripal to find it. Tripal will automatically place a link for your importer on the Drupal site at **admin > Tripal> Data Loaders**. + +Step 1: Importer Plugin Class File +---------------------------------- + +To create your importer, you will extend the ``ChadoImporterBase`` class which has several abstract functions that you must implement including: + +- form +- formSubmit +- formValidate +- run +- postRun + +Our example empty class looks like the following: .. code-block:: php @@ -23,161 +43,159 @@ The Tripal Chado module provides a base class named ``ChadoImporterBase`` that a namespace Drupal\tripal_example_importer\Plugin\TripalImporter; use Drupal\tripal_chado\TripalImporter\ChadoImporterBase; - use Drupal\Core\Ajax\AjaxResponse; - use Drupal\Core\Ajax\InvokeCommand; - use Drupal\Core\Ajax\ReplaceCommand; class ExampleImporter extends ChadoImporterBase { /** - * @see TripalImporter::form() + * @see ChadoImporterBase::form() */ public function form($form, &$form_state) { + // Always call the parent form. + $form = parent::form($form, $form_state); + + return $form; } /** - * @see TripalImporter::formSubmit() + * @see ChadoImporterBase::formSubmit() */ - public function formSubmit($form, &$form_state){ + public function formSubmit($form, &$form_state) { } /** - * @see TripalImporter::formValidate() + * @see ChadoImporterBase::formValidate() */ - public function formValidate($form, &$form_state){ + public function formValidate($form, &$form_state) { } /** - * @see TripalImporter::run() + * @see ChadoImporterBase::run() */ - public function run(){ + public function run() { } /** - * @see TripalImporter::postRun() + * @see ChadoImporterBase::postRun() */ - public function postRun(){ + public function postRun() { } - - /** - * @see TripalImporter::addAnalysis() - */ - public function addAnalysis($form, &$form_state) { - - } } -There is no need to include the importer via a ``require_once`` statement in your module file. Placing it in the ``/includes/TripalImporter/`` directory of your module is all you need for Tripal to find it. Tripal will automatically place a link for your importer at ``admin -> Tripal -> Data Loaders``. - -.. note:: - - If after creation of your importer file, Tripal does not show a link for it in the Data Loaders page, check that you have named your class file correctly and it is in the path described above. Sometimes a clear cache is necessary (``drush cc all``). - - -Static Variables +Class Annotations ----------------- -The next step in creation of your importer is setting the static member variables. Open the ``TripalImporter`` class file that comes with Tripal and found here ``tripal/includes/TripalImporter.inc``. Copy the ``public static`` member variables at the top of the class into your own class. For your importer, override any of the ``public static`` variables that need to be different from the default. - -.. note:: - - For the sake of simplicity in this document, many of the default settings are not changed, and therefore, not all are included. - -Our ``ExampleImporter`` class now appears as follows: +All Drupal Plugins require an `Annotation section `_ that appears as a PHP comment just above the Class definition. The annotation section provdies some basic settings that the TripalImporter plugin requires. As a quick example here is the Annotation section for the GFF3 importer. The GFF3 importer is provided by the Tripal Genome module and imports features defined in a GFF3 file into Chado. .. code-block:: php - /** - * @see TripalImporter - */ - class ExampleImporter extends TripalImporter { + * GFF3 Importer implementation of the ChadoImporterBase. + * + * @TripalImporter( + * id = "chado_fasta_loader", + * label = @Translation("Chado FASTA File Loader"), + * description = @Translation("Import a FASTA file into Chado"), + * file_types = {"fasta","txt","fa","aa","pep","nuc","faa","fna"}, + * upload_description = @Translation("Please provide a plain text file following the FASTA format specification."), + * upload_title = @Translation("FASTA File"), + * use_analysis = True, + * require_analysis = True, + * use_button = True, + * button_text = @Translation("Import FASTA file"), + * file_upload = True, + * file_remote = True, + * file_local = True, + * file_required = True, + * submit_disabled = False + * ) + */ + class GFF3Importer extends ChadoImporterBase { + +As you can see in the code above, the annotation section consists of multiple settings in key/value pairs. The meaning of each settings is as follows: + +- ``id``: A unique machine readable plugin ID for the loader. It must only contain alphanumeric characters and the underscore. It should be lowercase. +- ``label``: the human readable name (or label) for this importer. It is wrapped in a ``@Translation()`` function which will allow Drupal to provide translations for it. This label is shown to the user in the list of available data importers. +- ``description``: A short description for the site user that briefly indicates what this loader is for. It too is wrapped in a ``@Translation()`` function. This description is shown to the user for the loader. +- ``file_types``: A list of file extensions that the importer will allow to be uploaded. If a file does not have an extension in the list then it cannot be uploaded by the importer. +- ``upload_title``: Provides the title that should appear above the upload button. This helps the user understand what type of file is expected. +- ``upload_description``: Provides the information for the user related to the file upload. You can provide additional instructions or help text. +- ``use_analysis``: To support FAIR data principles, we should ensure that provenance of data is available. Chado provides the ``analysis`` table to link data to an analysis. The analysis record provides the details for how the data in the file was created or obtained. Set this to ``False`` if the loader should not require an analysis when loading. if ``use_analysis`` is set to ``True`` then the user will be presented with a form element to select an analysis and this analysis will be available to you for your importer. +- ``require_analysis``: If the ``use_analysis`` value is set then this value indicates if the analysis should be required. If ``True`` it will be required, otherwise it will be optional. +- ``button_text``: The text that should appear on the button at the bottom of the importer form. +- ``use_button``: Indicates whether a submit button should be present. This should only be ``False`` in situations were you need multiple buttons or greater control over the submit process (e.g., multi-page forms). +- ``submit_disabled``: Indicates whether the submit button should be disabled when the form appears. The form can then be programmatically enabled via AJAX once certain criteria is set. +- ``file_upload``: Indicates if the loader should provide a form element for uploading a file. +- ``file_remote``: Indicates if the loader should provide a form element for specifying the URL of a remote file. +- ``file_local``: Indicates if the loader should provide a form element for specifying the path available to the web server where the file is located. +- ``file_required``: Indicates if the file must be provided. + +For our ``ExampleImporter`` class we will set the annotations accordingly: - /** - * The name of this loader. This name will be presented to the site - * user. - */ - public static $name = 'Example TST File Importer'; - - /** - * The machine name for this loader. This name will be used to construct - * the URL for the loader. - */ - public static $machine_name = 'tripal_tst_loader'; - - /** - * A brief description for this loader. This description will be - * presented to the site user. - */ - public static $description = 'Loads TST files'; - - /** - * An array containing the extensions of allowed file types. - */ - public static $file_types = ['txt', 'tst', 'csv']; - - /** - * Provides information to the user about the file upload. Typically this - * may include a description of the file types allowed. - */ - public static $upload_description = 'TST is a fictional format. Its a 2-column, CSV file. The columns should be of the form featurename, and text'; +.. code-block:: php - /** - * Indicates the methods that the file uploader will support. - */ - public static $methods = [ - // Allow the user to upload a file to the server. - 'file_upload' => TRUE, - // Allow the user to provide the path on the Tripal server for the file. - 'file_local' => TRUE, - // Allow the user to provide a remote URL for the file. - 'file_remote' => TRUE, - ]; - } + /** + * TST Importer implementation of the ChadoImporterBase. + * + * @TripalImporter( + * id = "tripal_tst_loader", + * label = @Translation("Example TST File Importer"), + * description = @Translation("Loads TST files"), + * file_types = {"txt", "tst", "csv"}, + * upload_description = @Translation("TST is a fictional format. Its a 2-column, CSV file. The columns should be of the form featurename, and text"), + * upload_title = @Translation("TST File"), + * use_analysis = True, + * require_analysis = True, + * use_button = True, + * button_text = @Translation("Import TST file"), + * file_upload = True, + * file_remote = True, + * file_local = True, + * file_required = True, + * submit_disabled = False + * ) + */ + class ExampleImporter extends ChadoImporterBase { .. warning:: - The variables that are ``private static`` **should not** be copied and should not be changed. Only copy and change the ``public static`` member variables. - + You must use double quotes when specifying strings in the Annotations. -Now that we've given our importer a name and description, it will show up at ``/admin/tripal/loaders``: +Now that we have created the plugin and set it's annotations it should appear in the list of Tripal Importers at **admin > Tripal > Data Loaders** after we clear the Drupal cache (``drush cr``). .. image:: ./custom_data_loader.0.png +.. note:: -Form Components ------------------ - -By default, the ``TripalImporter`` class will provide the necessary upload widgets to allow a user to upload files for import. The static variables we set in the previous step dictate how that uploader appears to the user. However, for this example, our importer needs additional information from the user before data can be loaded. We need to provide additional form widgets. - -Typically, to create forms, Drupal provides form hooks: ``form``, ``form_validate``, ``form_submit``. The **TripalImporter** wraps these for us as class functions named ``form``, ``formValidate`` and ``formSubmit``. We can override these class functions to provide additional widgets to the form. + If your importer does not show in the list of data loaders, check the Drupal recent logs at **admin > Manage > Reports > Recent log messages** . -.. note:: +Using the annotation settings specified for our example importer, the importer form will automatically provide a **File Upload** field set, and an **Analysis** selector. The **File Upload** section lets users choose to upload a file, provide a server path to a file already on the web server or a specify a remote path for files located via a downloadable link on the web. The **Analysis** selector is important because it allows the user to specify an analysis that describes how the data file was created. It will look like the following screenshot: - Typically we only need to implement the ``form`` and ``formValidate`` functions. The ``formSubmit`` does not need to be modified. +.. image:: custom_data_loader.1.png -.. note:: +Customizing the Form +-------------------- - If you are not familiar with form creation in Drupal you may want to find a Drupal reference book that provides step-by-step instructions. Additionally, you can explore the `API documentation for form construction for Drupal 7 `_. Here, this example expects you are comfortable with form construction in Drupal. +Most likely you will want to customize the importer form. For our example TST file importer we want to read the file, split it into feature and values, and insert properties into the ``featureprop`` table of Chado. That table requires a controlled vocabulary term ID for the ``type_id`` column of the table. Therefore, we want to customize the importer form to request a controlled vocabulary term. To customize the form we can use three functions: +- ``form()``: Allows you to add additional form elements to the form. +- ``formValidate()``: Provides a mechanism by which you can validate the form elements you added. +- ``formSubmit()``: Allows you to perform some preprocessing prior to submission of the form. Typically this function does not need to be implemented--only if you want to do preprocessing before submission. -The form function -^^^^^^^^^^^^^^^^^ -To provide custom widgets for our importer we need to implement the ``form`` function. However, let's review the current form provided by the TripalImporter for us already. Using the static variables settings specified above the form automatically provides a **File Upload** field set, and an **Analysis** selector. The **File Upload** area lets users choose to upload a file, provide a **Server path** to a file already on the web server or a **Remote path** for files located via a downloadable link on the web. The **Analysis** selector is important because it allows the user to specify an analysis that describes how the data file was created. +.. note:: -.. image:: ./custom_data_loader.1.oob_file_interface.png + If you are not familiar with form creation in Drupal you may want to find a Drupal reference book that provides step-by-step instructions. Additionally, you can explore the `API documentation for form construction for Drupal 10 `_. -.. image:: ./custom_data_loader.2.oob_analysis_select.png -For our example TST file importer these upload options are sufficient. However, for our data import we want the user provide a CV term. We want our importer to read the file, split it into feature and values, and insert properties into the ``featureprop`` table of Chado using the the CV term as the ``type_id`` for the table. +The form() function +^^^^^^^^^^^^^^^^^^^ -To add a widget that allows the user to provide a CV term, we must implement the ``form`` function and include code using Drupal's Form API that will add the widget. +We can use the ``form()`` function to add an element to request a CV term. .. code-block:: php :name: ExampleImporter::form From 2170f23336d7a0c1f5c464c3e1d461c2eecdc746 Mon Sep 17 00:00:00 2001 From: Stephen Ficklin Date: Fri, 23 Feb 2024 16:15:45 -0800 Subject: [PATCH 3/5] continued updates --- .../biodata/custom_data_loader.2.png | Bin 0 -> 39459 bytes docs/dev_guide/biodata/importers.rst | 150 +++++++++--------- 2 files changed, 79 insertions(+), 71 deletions(-) create mode 100644 docs/dev_guide/biodata/custom_data_loader.2.png diff --git a/docs/dev_guide/biodata/custom_data_loader.2.png b/docs/dev_guide/biodata/custom_data_loader.2.png new file mode 100644 index 0000000000000000000000000000000000000000..498939f823de4b84c5d1fdc590239d084926d4af GIT binary patch literal 39459 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 )tN}=cvR5-=)?L^o5X7 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ǀ+In28}Bi?dTXs^@j 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%0AC!?WGgdN%&l(1U7d|3_vi^LE8{1i~F_ zy*;c-J%eeT|8;d)oOYq|0J=bK3S1g~a^mo}ZxOeeCks-)&TsqHh#gD~Qk9Rdhlhu6 zZP^9Vw+ zEp*l|xCa`yMz2kvs=$KgRLUK!3e0tMybWr4mp+Q%U2K{1KW`_NZ%o!qt~pDmcK7G> zhL8(^juMN>v{0n`8&n3)@ z$mr2OeivcYXN+GL{zEDl|M5}(`D<;wV?2tz+=_Ma5&h2#3eR=|V9WpcE7tcz)r&j4 zzRm`}SQAq2zANZzg-<%DF-e#|j8BhCU$V~yi~MQZ*8mYHMf*!42Az7jAx~87eK`Z? z{oRMVHGVBkm^Ap^Z}2K350*0Z=3!-yPrv)_MSQwh{LOKg0K{G7epTV}Gx}$F=?r(f`>c{9nBC|L=dz$NQfvuPgA(t=Em<8Zl%gl_c^I H&)@zx_^iNh literal 0 HcmV?d00001 diff --git a/docs/dev_guide/biodata/importers.rst b/docs/dev_guide/biodata/importers.rst index 9f0000f..2c35389 100644 --- a/docs/dev_guide/biodata/importers.rst +++ b/docs/dev_guide/biodata/importers.rst @@ -1,41 +1,54 @@ Creating a Chado Data Importer ============================== -Often we want to simplify import of data into Chado by provide a user interface by which a site developer can easily select a file, provide values for a few settings and click a button to load a file. Examples of existing loaders compatible with Tripal include the FASTA and GFF loaders that come with the Tripal Genome module. These loaders allow users to import data into Chado that are in FASTA or GFF format. If you would like to support loading of a file type you can create a new loader by implementing your own ``TripalImporter`` plugin and writing the code to insert or update the data into Chado. The ``TripalImporter`` plugin provides many conveniences. For example, it provides an input form that automatically handles files uploads, it performs job submission, logging, and provides progress updates during execution. Adding a ``TripalImporter`` to your module allows means anyone who installs your module can use your new loader! +Often we want to provide a user interface by which a site developer can easily import data into Chado. Examples of existing loaders compatible with Tripal include the FASTA and GFF3 loaders that come with the Tripal Genome module. These loaders allow users to import data into Chado that are in `FASTA `_ or `GFF3 format `_. -To document how to create a new importer, we will describe use of the ``TripalImporter`` class within the context of a new simple importer called the ``ExampleImporter``. This importer will read in a comma-separated file containing genomic features and their properties (a fictional "Test Format" file). The loader will split each line into feature and property values, and then insert each property into the ``featureprop`` table of Chado using a controlled vocabulary term (supplied by the user) as the ``type_id`` for the property. +If you would like to create a new data importer for Chado you will need to create your own **TripalImporter** plugin. The Tripal importers use the `Drupal Plugin API `_. The plugin infrastructure of Drupal allows a module to provide new functionality that builds off of a common interface. For importing data this interface is provided by the ``TripalImporterInterface`` class. The **TripalImporter** plugin provides many conveniences. For example, it provides an input form that automatically handles files uploads, it performs job submission, logging, and provides progress updates during execution. Adding a **TripalImporter** plugin to your module will allow anyone who installs your module to also use your new loader! + +Here, we will show how to create a **TripalImporter** plugin by building a simple importer called the **ExampleImporter**. This importer reads a comma-separated file containing genomic features and their properties (a fictional "Test Format" file). The loader will split each line into feature and property values, and then insert each property into the ``featureprop`` table of Chado using a controlled vocabulary term (supplied by the user) as the ``type_id`` for the property. .. note:: Prior to starting your data loader you should plan how the data will be imported into Chado. Chado is a flexible database schema and it may be challenging at times to decide in to which tables data should be placed. It is recommended to reach out to the Chado community to solicit advice. Doing so will allow you to share your loader will other Tripal users more easily! -About Drupal Plugins --------------------- -The Tripal importers use the `Drupal Plugin API `_. The plugin infrastructure of Drupal allows a module to provide new functtionality the builds off of a common interface (such as Tripal's importer interface). +Step 1: Create Your Module +-------------------------- +To create your an importer, you first need to have a Drupal module in which the loader will be provided. If you do not know how to create a module, see the section titled :doc:`../module_dev` for further direction. For this document we will describe creation of an importer in a fake module named ``tripal_example_importer``. + +Step 2: Create the Importer Class File +-------------------------------------- +To define a new ``TripalImporter`` plugin, you should first create the directory ``src/Plugin/TripalImporter/`` in your module. For the example here, we will create a new plugin named ``ExampleImporter``. We must name the file the same as the class (with a ``.php`` extension) and place the file in the ``src/Plugin/TripalImporter/`` directory we just created. For example: ``tripal_example_importer\src\Plugin\TripalImporter\ExampleImporter.inc``. Placing the importer class file in the ``src/Plugin/TripalImporter`` directory is all you need for Tripal to find it. Tripal will automatically place a link for your importer on the Drupal site at **admin > Tripal > Data Loaders**. + +Step 3: Stub the Class File +--------------------------- + +In the Class file created in the previous step we will write our **TripalImporter** plugin. First, we must set the namespace for this class. It should look similar to the path where the file is stored (but without the ``src`` directory): + +.. code-block:: php + Tripal> Data Loaders**. + class ExampleImporter extends ChadoImporterBase { -Step 1: Importer Plugin Class File ----------------------------------- -To create your importer, you will extend the ``ChadoImporterBase`` class which has several abstract functions that you must implement including: +All **TripalImporter** plugins uss the ``TripalImporterInterface`` which requires that several unctions are included in your plugin. These functions are: -- form -- formSubmit -- formValidate -- run -- postRun +- ``form()`` +- ``formSubmit()`` +- ``formValidate()`` +- ``run()`` +- ``postRun()`` -Our example empty class looks like the following: +We will discuss each fucntion later but for now, we will create "stubs" for each of these functions in our class. For our example empty class it should look like the following: .. code-block:: php @@ -88,9 +101,26 @@ Our example empty class looks like the following: } } -Class Annotations ------------------ -All Drupal Plugins require an `Annotation section `_ that appears as a PHP comment just above the Class definition. The annotation section provdies some basic settings that the TripalImporter plugin requires. As a quick example here is the Annotation section for the GFF3 importer. The GFF3 importer is provided by the Tripal Genome module and imports features defined in a GFF3 file into Chado. +Notice in the ``form()`` function there is a call to the ``parent::form()``: + +.. code-block:: php + + /** + * @see ChadoImporterBase::form() + */ + public function form($form, &$form_state) { + + // Always call the parent form. + $form = parent::form($form, $form_state); + + return $form; + } + +Without calling the ``parent::form() `` function your importer's form may not properly work. This is required. + +Step 4: Add Class Annotations +----------------------------- +All Drupal plugins require an `Annotation section `_ that appears as a PHP comment just above the Class definition. The annotation section provides settings that the **TripalImporter** plugin requires. As a quick example here is the Annotation section for the GFF3 importer. The GFF3 importer is provided by the Tripal Genome module and imports features defined in a GFF3 file into Chado. .. code-block:: php @@ -117,7 +147,7 @@ All Drupal Plugins require an `Annotation section Tripal > Data Loaders** after we clear the Drupal cache (``drush cr``). .. image:: ./custom_data_loader.0.png @@ -174,14 +206,14 @@ Now that we have created the plugin and set it's annotations it should appear in If your importer does not show in the list of data loaders, check the Drupal recent logs at **admin > Manage > Reports > Recent log messages** . -Using the annotation settings specified for our example importer, the importer form will automatically provide a **File Upload** field set, and an **Analysis** selector. The **File Upload** section lets users choose to upload a file, provide a server path to a file already on the web server or a specify a remote path for files located via a downloadable link on the web. The **Analysis** selector is important because it allows the user to specify an analysis that describes how the data file was created. It will look like the following screenshot: +Using the annotation settings we provided, the importer form will automatically provide a **File Upload** field set, and an **Analysis** selector. The **File Upload** section lets users choose to upload a file, provide a server path to a file already on the web server or a specify a remote path for files located via a downloadable link on the web. The **Analysis** selector is important because it allows the user to specify an analysis that describes how the data file was created. It will look like the following screenshot: .. image:: custom_data_loader.1.png -Customizing the Form --------------------- +Step 6: Customize the Form +-------------------------- -Most likely you will want to customize the importer form. For our example TST file importer we want to read the file, split it into feature and values, and insert properties into the ``featureprop`` table of Chado. That table requires a controlled vocabulary term ID for the ``type_id`` column of the table. Therefore, we want to customize the importer form to request a controlled vocabulary term. To customize the form we can use three functions: +Most likely, you will want to add elements the importer form. For our example TST file importer we want to split the file to retrieve feature and their properties, and then insert properties into the ``featureprop`` table of Chado. That table requires a controlled vocabulary term ID for the ``type_id`` column of the table. Therefore, we want to customize the importer form to request a controlled vocabulary term. To customize the form we can use three functions: - ``form()``: Allows you to add additional form elements to the form. - ``formValidate()``: Provides a mechanism by which you can validate the form elements you added. @@ -195,65 +227,41 @@ Most likely you will want to customize the importer form. For our example TST fi The form() function ^^^^^^^^^^^^^^^^^^^ -We can use the ``form()`` function to add an element to request a CV term. +We can use the ``form()`` function to add the element to request the property CV term. To help, Tripal provides a handy service for searching for a controlled vocabulary term, we can use this as part of a text box with an autocomplete. The following code shows the addition of a new ``textfield`` form element with a ``#autocomplete_route_name`` setting that tells the form to use Tripal's CV search service to support autocompletion as the user types. .. code-block:: php :name: ExampleImporter::form - public function form($form, &$form_state) { - - // For our example loader let's assume that there is a small list of - // vocabulary terms that are appropriate as properties for the genomics - // features. Therefore, we will provide an array of sequence ontology terms - // the user can select from. - $terms = [ - ['id' => 'SO:0000235'], - ['id' => 'SO:0000238'], - ['id' => 'SO:0000248'] - ]; - - // Construct the options for the select drop down. - $options = []; - // Iterate through the terms array and get the term id and name using - // appropriate Tripal API functions. - foreach ($terms as $term){ - $term_object = chado_get_cvterm($term); - $id = $term_object->cvterm_id; - $options[$id] = $term_object->name; - } - - // Provide the Drupal Form API array for a select box. - $form['pick_cvterm'] = [ - '#title' => 'CVterm', - '#description' => 'Please pick a CVterm. The loaded TST file will associate the values with this term as a feature property.', - '#type' => 'select', - '#default_value' => '0', - '#options' => $options, - '#empty_option' => '--please select an option--' + // Always call the parent form. + $form = parent::form($form, $form_state); + + // Add an element to the form to allow a user to pick + // a controlled vocabulary term. + $form['pick_cvterm'] = [ + '#title' => t('Property Type'), + '#type' => 'textfield', + '#required' => TRUE, + '#description' => t("Specify the controlled vocabulary term for " + . "properties that will be added to genomic features in the input file."), + '#autocomplete_route_name' => 'tripal_chado.cvterm_autocomplete', + '#autocomplete_route_parameters' => ['count' => 5, 'cv_id' => 0], ]; - // The form function must always return our form array. return $form; } -Our form now has a select box! - -.. image:: ./custom_data_loader.3.cvterm_select.png +The ``#autocomplete_route_parameters`` setting takes an array of two arguments: ``count`` and ``cv_id``. The ``count`` argument specifies the maximum number of matching CV terms that will be shown as the user types. The ``cv_id`` in the example is set to zero, indicating that there are no restrictions on which vocabulary the terms can come from. If you wanted to restrict the user to only selecting terms from a specific vocabulary then you would set the ``cv_id`` to the vocabulary ID from Chado. +Reloading the importer, the form now has an autocomplete text box for selecting a CV term. -Using AJAX in forms -""""""""""""""""""" - -.. note:: - - This section is not yet available. For now, check out the Drupal AJAX guide https://api.drupal.org/api/drupal/includes%21ajax.inc/group/ajax/7.x +.. image:: custom_data_loader.2.png -The formValidate function +The formValidate() function ^^^^^^^^^^^^^^^^^^^^^^^^^ -The ``formValidate`` function is responsible for verifying that the user supplied values from the form submission are valid. To warn the user of inappropriate values, the Drupal API function, ``form_set_error()`` is used. It provides an error message, highlights in red the widget containing the bad value, and prevents the form from being submitted--allowing the user to make corrections. In our example code, we will check that the user selected a CV term from the ``pick_cvterm`` widget. +The ``formValidate()`` function is responsible for verifying that the user supplied values from the form submission are valid. To warn the user of inappropriate values, the Drupal API function, ``form_set_error()`` is used. It provides an error message, highlights in red the widget containing the bad value, and prevents the form from being submitted--allowing the user to make corrections. In our example code, we will check that the user selected a CV term from the ``pick_cvterm`` widget. .. code-block:: php From 3eaabe155cffe7d741c88e4ff4ae114d6809922f Mon Sep 17 00:00:00 2001 From: Stephen Ficklin Date: Sat, 24 Feb 2024 10:57:43 -0800 Subject: [PATCH 4/5] updates --- docs/dev_guide/biodata/importers.rst | 254 +++++++-------------------- 1 file changed, 65 insertions(+), 189 deletions(-) diff --git a/docs/dev_guide/biodata/importers.rst b/docs/dev_guide/biodata/importers.rst index 2c35389..b14fbed 100644 --- a/docs/dev_guide/biodata/importers.rst +++ b/docs/dev_guide/biodata/importers.rst @@ -116,7 +116,7 @@ Notice in the ``form()`` function there is a call to the ``parent::form()``: return $form; } -Without calling the ``parent::form() `` function your importer's form may not properly work. This is required. +Without calling the ``parent::form()`` function your importer's form may not properly work. This is required. Step 4: Add Class Annotations ----------------------------- @@ -260,63 +260,59 @@ Reloading the importer, the form now has an autocomplete text box for selecting The formValidate() function -^^^^^^^^^^^^^^^^^^^^^^^^^ -The ``formValidate()`` function is responsible for verifying that the user supplied values from the form submission are valid. To warn the user of inappropriate values, the Drupal API function, ``form_set_error()`` is used. It provides an error message, highlights in red the widget containing the bad value, and prevents the form from being submitted--allowing the user to make corrections. In our example code, we will check that the user selected a CV term from the ``pick_cvterm`` widget. +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The ``formValidate()`` function is responsible for verifying that the user supplied values are valid. This function receives two arguments: ``$form`` and ``$form_validate``. The ``$form`` object contains the fully built form. The ``$form_validate`` argument contains the object that represents the user submitted state of the form. To warn the user of inappropriate values, the ``$form_state->setErrorByName()`` function is used. It provides an error message, highlights in red the widget containing the bad value, and prevents the form from being submitted--allowing the user to make corrections. In our example code, we will check that the user selected a CV term from the ``pick_cvterm`` widget. .. code-block:: php public function formValidate($form, &$form_state) { - // Always call the TripalImporter (i.e. parent) formValidate as it provides - // some important feature needed to make the form work properly. - parent::formValidate($form, $form_state); + // Get the values submitted by the user. + $form_state_values = $form_state->getValues(); + + // The pick_cvterm element is required and Drupal will handle that + // check for us, so we only need to make sure the user let the user selected + // a term from the autocomplete with the accession in parentheses. + $term = $form_state_values['pick_cvterm']; - // Get the chosen CV term form the form state and if there is no value - // set warn the user. - $chosen_cvterm = $form_state['values']['pick_cvterm']; - if ($chosen_cvterm == 0) { - form_set_error('pick_cvterm', 'Please choose a CVterm.'); + if (!preg_match('/\(.+?:.+?\)/', $term)) { + $form_state->setErrorByName('pick_cvterm', + t('Please choose a property type from the list that appears while typing. ' + . 'It must include the controlled vocabulary term accession')); } } -The implementation above looks for the ``pick_cvterm`` element of the ``$form_state`` and ensures the user selected something. This is a simple example. An implementation for a more complex loader with a variety of widgets will require more validation checks. +The implementation above gets the ``pick_cvterm`` element from the ``$form_state`` object. The PHP ``preg_match`` function uses a regular expression to make sure the term selected by the user has the format provided by the autocomplete (e.g., `comment (rdfs:comment)`). It checks to make sure the term accession is present in parentheses. For your importer, use this function to check as many form elements as you add to the importer. -.. note:: - - If our importer followed best practices, it would not need a validator at all. The cvterm select box in the form could be defined as below. Note the ``'#required' => True`` line: this would handle the validation for us. For this tutorial, however, we implement the validation ourselves to demonstrate the function. +The formSubmit() function +^^^^^^^^^^^^^^^^^^^^^^^^^ +If you need to perform any steps prior to running the importer you can use the ``formSubmit()`` function. Suppose we wanted to add to our form the ability for a user to add new terms that do not already exist in the database. We would create the form elements in the ``form()`` function, make sure we have validation checks in the ``formValidate()`` and then we could insert the new term into the database prior to job submission in the ``formSubmit()`` function. Most likely you will not need to use this function. For most existing importers provided by Tripal this function is not used. - .. code-block:: php - // Provide the Drupal Form API array for a select box. - $form['pick_cvterm'] = [ - '#title' => 'CVterm', - '#description' => 'Please pick a CVterm. The loaded TST file will associate the values with this term as a feature property.', - '#type' => 'select', - '#default_value' => '0', - '#options' => $options, - '#empty_option' => '--please select an option--' - '#required' => True - ]; +Step 7: Write Importing Code +----------------------------- +When an importer form is submitted and passes all validation checks, a job is automatically added to the :doc:`../../admin_guide/jobs` system. The ``TripalImporter`` parent class does this for us! The :doc:`../../admin_guide/jobs` system is meant to allow long-running jobs to execute behind-the-scenes on a regular time schedule. As jobs are added they are executed in order. Therefore, if a user submits a job using the importer's form then the :doc:`../../admin_guide/jobs` system will automatically run the job the next time it is scheduled to run or it can be launched manually by the site administrator. +When the **Tripal Job** system executes an importer job it will call three different functions: -When an importer form is submitted and passes all validation checks, a job is automatically added to the **Tripal Job** system. The ``TripalImporter`` parent class does this for us! The **Tripal Job** system is meant to allow long-running jobs to execute behind-the-scenes on a regular time schedule. As jobs are added they are executed in order. Therefore, if a user submits a job using the importer's form then the **Tripal Job** system will automatically run the job the next time it is scheduled to run or it can be launched manually by the site administrator. +- ``run()``: contains the code that performs the import of the file. +- ``preRun()``: contains code to be executed prior to the the ``run()`` function. +- ``postRun()``: contains code to be executed after executiong of the ``run()` function. +These functions were added to our class as "stubs" in Step 3 above and now we discuss each of these. -Importer Execution ------------------- -The ``form`` and ``formValidate`` functions allow our Importer to receive an input file and additional values needed for import of the data. To execute loading a file the ``TripalImporter`` provides several additional overridable functions: ``run``, ``preRun`` and ``postRun``. When the importer is executed, the ``preRun`` function is called first. It allows the importer to perform setup prior to full execution. The ``run`` function is where the full execution occurs and the ``postRun`` function is used to perform "cleanup" prior to completion. For our ``ExampleImporter`` class we only need to implement the ``run`` function. We have no need to perform any setup or cleanup outside of the typical run. +The preRun() function +^^^^^^^^^^^^^^^^^^^^^ +The ``preRun()`` function is called automatically by Tripal and should contain code that must be executed prior to running hte importer. This function provide any setup that is needed prior to importing the file. In the case of our example importer, we will not need to use the ``preRun()`` function so it will remain empty. -The run function -^^^^^^^^^^^^^^^^ -The ``run`` function is called automatically when Tripal runs the importer. For our ``ExampleImporter``, the run function should collect the values provided by the user, read and parse the input file and load the data into Chado. The first step, is to retrieve the user provided values and file details. The inline comments in the code below provide instructions for retrieving these details. +The run() function +^^^^^^^^^^^^^^^^^^ +The ``run()`` function is called automatically when Tripal runs the importer. For our ``ExampleImporter``, the run function should read and parse the input file and load the data into Chado. The first step, is to retrieve the user provided values from the form and the file details. The inline comments in the code below provide instructions for retrieving these details. .. code-block:: php - /** - * @see TripalImporter::run() - */ public function run() { // All values provided by the user in the Importer's form widgets are @@ -333,8 +329,11 @@ The ``run`` function is called automatically when Tripal runs the importer. For // provided as an argument. $analysis_id = $arguments['analysis_id']; - // Any of the widgets on our form are also available as an argument. - $cvterm_id = $arguments['pick_cvterm']; + // Convert the cvterm text provided by the user submitted form + // to the actual cvterm ID from chado. + $cvterm = $arguments['pick_cvterm']; + $cv_autocomplete = new ChadoCVTermAutocompleteController(); + $cvterm_id = $cv_autocomplete->getCVtermId($cvterm); // Now that we have our file path, analysis_id and CV term we can load // the file. We'll do so by creating a new function in our class @@ -342,176 +341,53 @@ The ``run`` function is called automatically when Tripal runs the importer. For $this->loadMyFile($analysis_id, $file_path, $cvterm_id); } -.. note:: +In the example code above the ``loadMyFile()`` function is a function we add to our importer class that completes the loading of the file. We do not show the code of that function here, but it will be responsible for reading in the file provided by the ``$file_path`` variable and import the feature properties into Chado. - We do not need to validate in the ``run`` function that all of the necessary values in the arguments array are valid. Remember, this was done by the ``formValidate`` function when the user submitted the form. Therefore, we can trust that all of the necessary values we need for the import are correct. That is of course provided our ``formValidate`` function sufficiently checks the user input. +Logging +^^^^^^^ +During execution of our importer it is often useful to inform the user of progress, status and issues encountered. All **TripalImporter** plugins have several built-in objects and functions that support logging and reporting of progress. For logging, each importer has access to a **TripalLogger** accessible as ``$this->logger`` which uses the `Drupal Logging API `_. There are several functions that you can use with the logger than can report errors, warnings, notices or debugging information. A quick list of these are: -Importing the File -^^^^^^^^^^^^^^^^^^ -To keep the ``run`` function small, we will implement a new function named ``loadMyFile`` that will perform parsing and import of the file into Chado. As seen in the code above, the ``loadMyFile`` function is called in the ``run`` function. - -Initially, lets get a feel for how the importer will work. Lets just print out the values provided to our importer: +- ``$this->logger->emergency($message)`` +- ``$this->logger->alert($message)`` +- ``$this->logger->critical($message)`` +- ``$this->logger->error($message)`` +- ``$this->logger->warning($message)`` +- ``$this->logger->notice($message)`` +- ``$this->logger->info($message)`` +- ``$this->logger->debug($message)`` +For each of the functions above, the ``$message`` argument should contain the text that is reported. The following is an example code from the GFF3 loader where logging is used to report progress of each step: .. code-block:: php - public function loadMyFile($analysis_id, $file_path, $cvterm){ - var_dump(["this is running!", $analysis_id, $file_path, $cvterm]); - } - -To test our importer navigate to ``admin > Tripal > Data Importers`` and click the link for our TFT importer. Fill out the form and press submit. If there are no validation errors, we'll receive notice that our job was submitted and given a command to execute the job manually. For example: - -.. - - drush trp-run-jobs --username=admin --root=/var/www/html - - -If we execute our importer we should see the following output: - - -.. code-block:: bash - - Calling: tripal_run_importer(146) - - Running 'Example TST File Importer' importer - NOTE: Loading of file is performed using a database transaction. - If it fails or is terminated prematurely then all insertions and - updates are rolled back and will not be found in the database - - array(4) { - [0]=> - string(16) "This is running!" - [1]=> - string(3) "147" - [2]=> - string(3) "695" - [3]=> - string(72) "/Users/chet/UTK/tripal/sites/default/files/tripal/users/1/expression.tsv" - } - - Done. - - Remapping Chado Controlled vocabularies to Tripal Terms... + $this->logger->notice("Step 1 of 27: Caching GFF3 file..."); + +.. note:: -As you can see, running the job executes our run script, and we have all the variables we need to load the data. All we need to do now is write the code! + Do not use ``print`` or ``print_r`` statements as a way to inform the user of warnings, errors or progress. -To import data into Chado we will use the Tripal API. After splitting each line of the input file into a genomic feature and its property, we will use the ``chado_select_record`` to match the feature's name with a record in the ``feature`` table of Chado, and the ``chado_insert_property`` to add the property value. +Throwing errors +^^^^^^^^^^^^^^^ +The **TripalImporter** plugins can throw errors if needed. Tripal will catch the error, perform appropriate logging and recover gracefully. An example of throwing an error from the GFF3 loader: .. code-block:: php - public function loadMyFile($analysis_id, $file_path, $cvterm_id){ - - // We want to provide a progress report to the end-user so that they: - // 1) Recognize that the loader is not hung if running a large file, but is - // executing - // 2) Provides some indication for how long the file will take to load. - // - // Here we'll get the size of the file and tell the TripalImporter how - // many "items" we have to process (in this case bytes of the file). - $filesize = filesize($file_path); - $this->setTotalItems($filesize); - $this->setItemsHandled(0); - - // Loop through each line of file. We use the fgets function so as not - // to load the entire file into memory but rather to iterate over each - // line separately. - $bytes_read = 0; - $in_fh = fopen($file_path, "r"); - while ($line = fgets($in_fh)) { - - // Calculate how many bytes we have read from the file and let the - // importer know how many have been processed so it can provide a - // progress indicator. - $bytes_read += drupal_strlen($line); - $this->setItemsHandled($bytes_read); - - // Remove any trailing white-space from the line. - $line = trim($line); - - // Split line on a comma into an array. The feature name appears in the - // first "column" of data and the property in the second. - $cols = explode(",", $line); - $feature_name = $cols[0]; - $this_value = $cols[1]; - - // Our file has a header with the name 'Feature name' expected as the - // title for the first column. If we see this ignore it. - if ($feature_name == 'Feature name'){ - continue; - } - - // Using the name of the feature from the file, see if we can find a - // record in the feature table of Chado that matches. Note: in reality - // the feature table of Chado has a unique constraint on the uniquename, - // organism_id and type_id columns of the feature table. So, to ensure - // we find a single record ideally we should include the organism_id and - // type_id in our filter and that would require more widgets on our form! - // For simplicity, we will just search on the uniquename and hope we - // find unique features. - $match = ['uniquename' => $feature_name]; - $results = chado_select_record('feature', ['feature_id'], $match); - - // The chado_select_record function always returns an array of matches. If - // we found no matches then this feature doesn't exist and we'll skip - // this line of the file. But, log this issue so the user knows about it. - if (count($results) == 0) { - $this->logMessage('The feature, !feature, does not exist in the database', - ['!feature' => $feature_name], TRIPAL_WARNING); - continue; - } - - // If we failed to find a unique feature then we should warn the user - // but keep on going. - if (count($results) == 0) { - $this->logMessage('The feature, !feature, exists multiple times. ' . - 'Cannot add a property', ['!feature' => $feature_name], TRIPAL_WARNING); - continue; - } - - // If we've made it this far then we have a feature and we can do the - // insert. - $feature = $results[0]; - $record = [ - 'table' => 'feature', - 'id' => $feature->feature_id - ]; - $property = [ - 'type_id' => $cvterm_id, - 'value' => $this_value, - ]; - $options = ['update_if_present' => TRUE]; - chado_insert_property($record, $property, $options); - } - } - -Logging and Progress --------------------- -During execution of our importer it is often useful to inform the user of progress, status and issues encountered. There are several functions to assist with this. These include the ``logMessage``, ``setTotalItems`` and ``setItemsHandled`` functions. All three of these functions were used in the sample code above of the ``loadMyFile`` function. Here, we provide a bit more detail. - -The logMessage function -^^^^^^^^^^^^^^^^^^^^^^^ -The ``logMessage`` function is meant to allow the importer to provide status messages to the user while the importer is running. The function takes three arguments: + throw new \Exception(t('Cannot find landmark feature type \'%landmark_type\'.', + ['%landmark_type' => $this->default_landmark_type])); -1) a message string. -2) an array of substitution values. -3) a message status. +After an error is caught by Tripal, all database changes will be rolled back and any changes made to the database during the process of running the importer will no longer exist. -The message string contains the message for the user. You will notice that no variables are included in the string but rather tokens are used as placeholders for variables. This is a security feature provided by Drupal. Consider these lines from the code above: - -.. code-block:: php - - $this->logMessage('The feature, !feature, does not exist in the database', - ['!feature' => $feature_name], TRIPAL_WARNING); +Reporting Progress +^^^^^^^^^^^^^^^^^^ +For progress reporting, each importer can utilze two different functions: -Notice that ``!feature`` is used in the message string as a placeholder for the feature name. The mapping of ``!feature`` to the actually feature name is provided in the array provided as the second argument. The third argument supports several message types including ``TRIPAL_NOTICE``, ``TRIPAL_WARNING`` and ``TRIPAL_ERROR``. The message status indicates a severity level for the message. By default if no message type is provided the message is of type ``TRIPAL_NOTICE``. +- ``$this->setTotalItems()``: Indicates the total number of items (or steps) that must be processed for the laoder to complete. +- ``$this->setItemsHandled()``: Reports the total number of items that have been handled. -Any time the ``logMessage`` function is used the message is stored in the job log, and a site admin can review these logs by clicking on the job in the ``admin > Tripal > Tripal Jobs`` page. -.. note:: - You should avoid using ``print`` or ``print_r`` statements in a loader to provide messages to the end-user while loading the file. Always use the ``logMessage`` function to ensure all messages are sent to the job's log. The setTotalItems and setItemsHandled functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 383341796015dc8e76c0c7f8dd2e8acd7d6bab24 Mon Sep 17 00:00:00 2001 From: Stephen Ficklin Date: Sat, 24 Feb 2024 17:13:50 -0800 Subject: [PATCH 5/5] ready for PR --- docs/dev_guide/biodata/importers.rst | 184 ++++++++++++++++++++------- 1 file changed, 139 insertions(+), 45 deletions(-) diff --git a/docs/dev_guide/biodata/importers.rst b/docs/dev_guide/biodata/importers.rst index b14fbed..1bf2338 100644 --- a/docs/dev_guide/biodata/importers.rst +++ b/docs/dev_guide/biodata/importers.rst @@ -296,8 +296,8 @@ When an importer form is submitted and passes all validation checks, a job is au When the **Tripal Job** system executes an importer job it will call three different functions: -- ``run()``: contains the code that performs the import of the file. - ``preRun()``: contains code to be executed prior to the the ``run()`` function. +- ``run()``: contains the code that performs the import of the file. - ``postRun()``: contains code to be executed after executiong of the ``run()` function. These functions were added to our class as "stubs" in Step 3 above and now we discuss each of these. @@ -363,9 +363,9 @@ For each of the functions above, the ``$message`` argument should contain the te $this->logger->notice("Step 1 of 27: Caching GFF3 file..."); -.. note:: +.. warning:: - Do not use ``print`` or ``print_r`` statements as a way to inform the user of warnings, errors or progress. + Do not use ``print`` or ``print_r`` statements as a way to inform the user of warnings, errors or progress. These will not be logged and may interfere with functional testing. Throwing errors @@ -381,73 +381,167 @@ After an error is caught by Tripal, all database changes will be rolled back and Reporting Progress ^^^^^^^^^^^^^^^^^^ -For progress reporting, each importer can utilze two different functions: +For progress reporting, **TripalImporter** plugins can utilize two different functions: -- ``$this->setTotalItems()``: Indicates the total number of items (or steps) that must be processed for the laoder to complete. +- ``$this->setTotalItems()``: Indicates the total number of items (or steps) that must be processed for the importer to complete. - ``$this->setItemsHandled()``: Reports the total number of items that have been handled. +An **item** is an arbitrary term indicating some countable "units" that will be processed by our importer. This can be lines in a file, bytes in a file, or steps that an importer performs. To initialize the progress, first set the number of items handled to zero: + +.. code-block:: php + + $this->setItemsHandled(0); +Next indicate how many items you plan to process: +.. code-block:: php -The setTotalItems and setItemsHandled functions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The ``TripalImporter`` class is capable of providing progress updates to the end-user while the importer job is running. This is useful as it gives the end-user a sense for how long the job will take. As shown in the sample code above for the ``loadMyFile`` function, The first step is to tell the ``TripalImporter`` how many items need processing. An **item** is an arbitrary term indicating some measure of countable "units" that will be processed by our importer. + $this->setTotalItems($num_items); -In the code above we consider a byte as an item, and when all bytes from a file are read we are done loading that file. Therefore the ``setTotalItems`` function is used to tell the importer how many bytes we need to process. As we read each line, we count the number of bytes read and provide that number to the ``setItemsHandled`` function. The ``TripalImporter`` class will automatically calculate progress and print a message to the end-user indicating the percent complete, and some additional details such as the total amount of memory consumed during the loading. +Then, as you process each item in the loader you can rerun the ``setItemsHandled()`` function and update the number of items that have been handled. -.. note:: +Step 8: Write Functional Tests +------------------------------ +Functional testing is a critically important component of any software project. You should always strive to write tests for your software to ensure that the software performs as expected and bugs are less likely to enter the code. Drupal provides `automated testing `_ by integrated the ``phpunit`` testing framework. We can create functional tests by utilizing this infrastructure provided by Drupal. - All importers are different and the "item" need not be the number of bytes in the file. However, if you want to provide progress reports you must identify an "item" and the total number of items there are for processing. +Create the Testing Class +^^^^^^^^^^^^^^^^^^^^^^^^ +Tests for **TripalImporters** are Class files that should be placed in the ``tests/src/Kernel/Plugin/TripalImporter`` folder of your module and the file should have the same name as the importer class with a "Test" suffix. For our example importer it would be found in this location ``tripal_example_importer\tests\src\Kernel\Plugin\TripalImporter\ExampleImporterTest.inc``. -Testing Importers ------------------- -Unit Testing is a critically important component of any software project. You should always strive to write tests for your software. Tripal provides unit testing using the ``phpunit`` testing framework. The Tripal Test Suite provides a strategy for adding tests for your new Importer. It will automatically set up and bootstrap Drupal and Tripal for your testing environment, as well as provide database transactions for your tests, and factories to quickly generate data. We will use the Tripal Test Suite to provide unit testing for our ``ExampleImporter``. +The testing class should have the same name as the file and should extend the ``ChadoTestKernelBase``. The following example code shows the empty starter class for our ``ExampleImporterTest`` class: -.. note:: - Before continuing, please install and configure Tripal Test Suite. +.. code-block:: php - For instructions on how to install, configure, and run Tripal Test Suite, `please see the Tripal Test Suite documentation. `_ + namespace Drupal\Tests\tripal_chado\Kernel\Plugin\TripalImporter; + use Drupal\Core\Url; + use Drupal\Tests\tripal_chado\Kernel\ChadoTestKernelBase; -Example file -^^^^^^^^^^^^ -When developing tests, consider including a small example file as this is good practice both to ensure that your loader works as intended, and for new developers to easily see the expected file format. For our ``ExampleImporter``, we'll include the following sample file and store it in this directory of our module: ``tests/data/example.txt``. + /** + * Tests the functionality of the ExampleImporter Importer. + * + */ + class ExampleImporterTest extends ChadoTestKernelBase { + + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + } + + /** + * Tests the importer form. + */ + public function testImporterForm() { + + } -.. csv-table:: Example input file - :header: "Feature name", "CVterm value" + /** + * Tests the run function. + */ + public function testRun() { + } + } - "test_gene_1", "blue" - "test_gene_2", "red" +During automated testing, a new temporary instance of Drupal is created. Drupal will run each test class and for each test class, the ``setUp()`` function will be run first. Afterwards, all of the functions that have the prefix ``test`` will be executed. -Loading the Importer +The setUp() function ^^^^^^^^^^^^^^^^^^^^ -Testing your loader requires a few setup steps. First, TripalImporters are not explicitly loaded in your module (note that we never use ``include_once()`` or ``require_once`` in the ``.module`` file). Normally Tripal finds the importer automatically, but for unit testing we must include it to our test class explicitly. Second, we must initialize an instance of our importer class. Afterwards we can perform any tests to ensure our loader executed properly. The following function provides an example for setup of the loader for testing: +The ``setup()`` function allows you to prepare the test Drupal site so that it is ready for the tests that follow. The following code provides a common set of steps that all **TripalImporters** should use to setup the class for testing: .. code-block:: php - private function run_loader(){ + /** + * {@inheritdoc} + */ + protected function setUp(): void { + + // Always call the parent::setUp function. + parent::setUp(); + + // Ensure we see all logging in tests. + \Drupal::state()->set('is_a_test_environment', TRUE); + + // Open a connection to Chado. This will ensure we have a properly + // prepared Chado database. + $this->connection = $this->getTestSchema(ChadoTestKernelBase::PREPARE_TEST_CHADO); + + // Ensure we can access file_managed related functionality from Drupal. + // ... users need access to system.action config? + $this->installConfig('system'); + // ... managed files are associated with a user. + $this->installEntitySchema('user'); + // ... Finally the file module + tables itself. + $this->installEntitySchema('file'); + $this->installSchema('file', ['file_usage']); + } + +In the ``setUp()`` function above, we first allow the parent class to perform its setup functions. Then we ensure the logger messages are set to be captured for testing, Chado is property initialized and the test supports managed files. - // Load our importer into scope. - module_load_include('inc', 'tripal_example_importer', 'includes/TripalImporter/ExampleImporter'); +The testImporterForm() function +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +For our first, test, we will write code to ensure that the user interface form is working as intended. Here we will test that all of the form elements that out importer added to the form are working as expected. You do not need to write tests for the file uploader nor for the analysis selection element. The testing of these elements will happen by the parent classes. Here we only need to test our additions to the form. - // Create an array of arguments we'll use for testing our importer. - $run_args = [ - 'analysis_id' => $some_analysis_id, - 'cvterm' => $some_cvterm_id - ]; - $file = ['file_local' => __DIR__ . '/../data/exampleFile.txt']; +To perform tests, the ``ChadoTestKernelBase`` class automatically provides a set of `PHPUnit assertion functions `_. For example, to test a boolean variable is ``True`` you would use the `assertTrue() `_ function in the following way: + +.. code-block:: php - // Create a new instance of our importer. - $importer = new \ExampleImporter(); - $importer->create($run_args, $file); + $this->assertTrue($my_boolean_var, "The variable is not a boolean."); - // Before we run our loader we must let the TripalImporter prepare the - // files for us. - $importer->prepareFiles(); - $importer->run(); - } -.. note:: +Note that the assertion functions are available in your test class a member function (via ``$this->assertTrue()``). All assertion functions are available in this way. For our example importer we only need to test the property cvterm element. T + +For our example importer, the following code shows how we can test the form: + +.. code-block:: php + + /** + * Tests the importer form. + */ + public function testImporterForm() { + + // Store the plugin ID and label for easy access later. + $plugin_id = 'tripal_tst_loader'; + $importer_label = 'Loads TST files'; + + // Build the form using the Drupal form builder. + $form = \Drupal::formBuilder()->getForm('Drupal\tripal\Form\TripalImporterForm',$plugin_id); + + // Ensure we are able to build the form. + $this->assertIsArray($form, + "We expect the form builder to return a form but it did not."); + $this->assertEquals('tripal_admin_form_tripalimporter', $form['#form_id'], + "We did not get the form id we expected."); + + // Now that we have provided a plugin_id, we expect it to have a title matching our importer label. + $this->assertArrayHasKey('#title', $form, + "The form should have a title set."); + $this->assertEquals($importer_label, $form['#title'], + "The title should match the label annotated for our plugin."); + + // The plugin_id stored in a value form element. + $this->assertArrayHasKey('importer_plugin_id', $form, + "The form should have an element to save the plugin_id."); + $this->assertEquals($plugin_id, $form['importer_plugin_id']['#value'], + "The importer_plugin_id[#value] should be set to our plugin_id."); + + // The form has a submit button. + $this->assertArrayHasKey('button', $form, + "The form should have a submit button since we indicated a specific importer."); + + // Make sure the importer requires an analysis. + $this->assertArrayHasKey('analysis_id', $form, + "The from should not include analysis element, yet one exists."); + + // We should also have our importer-specific form elements added to the form! + $this->assertArrayHasKey('pick_cvterm', $form, + "The form should include an the 'pick_cvterm' form element."); + + } + +.. error:: - We highly recommend you make use of database transactions in your tests, especially when running loaders. Simply add ``use DBTransaction;`` at the start of your test class. Please see the `Tripal Test Suite documentation for more information `_. \ No newline at end of file + The documentation about testing is not yet complete. More information is needed to describe how to test form submission, the ``run()``, ``preRun()`` and ``postRun()``