diff --git a/trpcultivate_phenotypes/src/Controller/TripalCultivatePhenotypesSettingsController.php b/trpcultivate_phenotypes/src/Controller/TripalCultivatePhenotypesSettingsController.php index 8b63284d..4edb25aa 100644 --- a/trpcultivate_phenotypes/src/Controller/TripalCultivatePhenotypesSettingsController.php +++ b/trpcultivate_phenotypes/src/Controller/TripalCultivatePhenotypesSettingsController.php @@ -1,35 +1,62 @@ module_handler = $module_handler; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('module_handler') + ); + } + + /** + * Provides an administrative list of phenotypes configuration pages. + * + * @return array + * A render array consisting of a details element for each configuration + * page where the title is the configuration section and the contents + * include a short description plus a link. */ public function loadPage() { - // Quick enabled or disabled status of sub-phenotypes modules - // and report to dashboard. - $moduleHandler = \Drupal::service('module_handler'); + // Quick enabled or disabled status of sub-phenotypes modules and report + // to dashboard. $status_message = 'Tripal Cultivate Phenotypes Modules Status: '; - foreach(['trpcultivate_phenoshare', 'trpcultivate_phenocollect'] as $m) { - $is_enabled = ($moduleHandler->moduleExists($m)) ? 'is enabled' : 'is disabled'; + foreach (['trpcultivate_phenoshare', 'trpcultivate_phenocollect'] as $m) { + $is_enabled = ($this->module_handler->moduleExists($m)) ? 'is enabled' : 'is disabled'; $status_message .= '*' . $m . ' ' . $is_enabled . ' '; } @@ -37,8 +64,7 @@ public function loadPage() { $link = Link::fromTextAndUrl('Manage Modules', $url) ->toString(); - $this->messenger()->addStatus($this->t($status_message . '- @manage', ['@manage' => $link])); - + $this->messenger()->addStatus($status_message . ' - ' . $link); // Describe R Rules configuration: $url = Url::fromRoute('trpcultivate_phenotypes.settings_r'); @@ -90,4 +116,5 @@ public function loadPage() { return $element; } -} \ No newline at end of file + +} diff --git a/trpcultivate_phenotypes/src/Form/TripalCultivatePhenotypesOntologySettingsForm.php b/trpcultivate_phenotypes/src/Form/TripalCultivatePhenotypesOntologySettingsForm.php index 43ecb825..a9ed9d9f 100644 --- a/trpcultivate_phenotypes/src/Form/TripalCultivatePhenotypesOntologySettingsForm.php +++ b/trpcultivate_phenotypes/src/Form/TripalCultivatePhenotypesOntologySettingsForm.php @@ -148,10 +148,14 @@ public function buildForm(array $form, FormStateInterface $form_state) { $link_to_docs = Link::fromTextAndUrl($this->t('Tripal 4 User Guide'), $url) ->toString(); + $placeholder_values = [ + '@tripaljobs' => $link_to_jobs, + '@tripaldocs' => $link_to_docs, + ]; $config_warning = $this->t('Tripal Cultivate Phenotypes module requires controlled vocabulary terms and genus records used for creating terms and genus-ontology module configuration. If you already know how to execute a Tripal Job, please proceed with the Tripal Job Id number for Tripal Job titled: Tripal Cultivate Phenotypes: Install Ontology and Terms - (@tripaljobs), otherwise, please visit @tripaldocs to learn more about Tripal Jobs.', ['@tripaljobs' => $link_to_jobs, '@tripaldocs' => $link_to_docs]); + (@tripaljobs), otherwise, please visit @tripaldocs to learn more about Tripal Jobs.', $placeholder_values); $this->messenger()->addWarning($config_warning); return $form; @@ -325,9 +329,9 @@ public function buildForm(array $form, FormStateInterface $form_state) { // Render each term as autocomplete field element. foreach ($this->config_vars['terms'] as $config => $prop) { // Field description. - $describe = $this->t($prop['help_text']); + $describe = $prop['help_text']; // Field placeholder and title text. - $placeholder = $title = $this->t(ucwords($prop['name'])); + $placeholder = $title = ucwords($prop['name']); // Field default value. $config_value = $this->service_terms->getTermId($config); $default_value = ChadoCVTermAutocompleteController::formatCVterm($config_value); diff --git a/trpcultivate_phenotypes/src/Form/TripalCultivatePhenotypesRSettingsForm.php b/trpcultivate_phenotypes/src/Form/TripalCultivatePhenotypesRSettingsForm.php index de0de6c6..e9b32e6a 100644 --- a/trpcultivate_phenotypes/src/Form/TripalCultivatePhenotypesRSettingsForm.php +++ b/trpcultivate_phenotypes/src/Form/TripalCultivatePhenotypesRSettingsForm.php @@ -1,10 +1,5 @@ config(static::SETTINGS); $config_r = 'trpcultivate.phenotypes.r_config.'; - + $form['description'] = [ '#markup' => $this->t('Tripal Cultivate Phenotypes supports R language for statistical computing by providing - syntactically valid version of trait or values. Use R Transformation Rules configuration page to define - standard transformation rules to apply to trait or string when converting to R version.') + syntactically valid version of trait or values. Use R Transformation Rules configuration page to define + standard transformation rules to apply to trait or string when converting to R version.'), ]; $form['words'] = [ '#type' => 'textarea', '#title' => $this->t('List of words to remove'), '#default_value' => implode(',', $config->get($config_r . 'words')), - '#description' => $this->t('Separate each word entry with a comma character. + '#description' => $this->t('Separate each word entry with a comma character. Words must at least be 2 characters or more.'), '#required' => TRUE, ]; @@ -58,7 +55,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { '#type' => 'textarea', '#title' => $this->t('List of special characters to remove'), '#default_value' => implode(',', $config->get($config_r . 'chars')), - '#description' => $this->t('Separate each character entry with a comma character. + '#description' => $this->t('Separate each character entry with a comma character. Characters must be 1 character only.'), '#required' => TRUE, ]; @@ -67,12 +64,11 @@ public function buildForm(array $form, FormStateInterface $form_state) { '#type' => 'textarea', '#title' => $this->t('Match word and replace with'), '#default_value' => implode(',', $config->get($config_r . 'replace')), - '#description' => $this->t('Separate match and replace pairs with a comma character. + '#description' => $this->t('Separate match and replace pairs with a comma character. Use match = replace pattern for each combination.'), '#required' => TRUE, ]; - - + return parent::buildForm($form, $form_state); } @@ -82,21 +78,21 @@ public function buildForm(array $form, FormStateInterface $form_state) { public function validateForm(array &$form, FormStateInterface $form_state) { // Words: words must be at least 2 characters long. if ($words = $form_state->getValue('words')) { - foreach(explode(',', $words) as $word) { + foreach (explode(',', $words) as $word) { if (empty($word) || !preg_match('/\w{2,}/', $word)) { $form_state->setErrorByName('word', $this->t('Could not save rule. Empty or invalid word: @word added to the list.', ['@word' => $word])); } } } - + // Special characters: 1 character only, excluding comma symbol since // it is used as delimiter. if ($chars = $form_state->getValue('chars')) { - foreach(explode(',', $chars) as $char) { + foreach (explode(',', $chars) as $char) { if (empty($char) || $char == ',' || !preg_match('/\W{1}/', $char)) { $form_state->setErrorByName('chars', $this->t('Could not save rule. - Empty or invalid special characters: @char added to the list.', ['@char' => $char])); + Empty or invalid special characters: @char added to the list.', ['@char' => $char])); } } } @@ -104,11 +100,11 @@ public function validateForm(array &$form, FormStateInterface $form_state) { // Match and replace: match = replace pattern, excluding comma symbol since // it is used as delimiter. if ($replaces = $form_state->getValue('replace')) { - foreach(explode(',', $replaces) as $replace) { + foreach (explode(',', $replaces) as $replace) { if (empty($replace) || !preg_match('/^[^,]+\s{1}[=]\s{1}[^,]+$/', $replace)) { - $form_state->setErrorByName('replace', $this->t('Could not save rule. - Empty or invalid match and replace: @replace added to the list.', ['@replace' => $replace])); - } + $form_state->setErrorByName('replace', $this->t('Could not save rule. + Empty or invalid match and replace: @replace added to the list.', ['@replace' => $replace])); + } } } } @@ -118,8 +114,8 @@ public function validateForm(array &$form, FormStateInterface $form_state) { */ public function submitForm(array &$form, FormStateInterface $form_state) { $config_r = 'trpcultivate.phenotypes.r_config.'; - - // Configuration in field are string, convert to array to match + + // Configuration in field are string, convert to array to match // configuration schema data type. $this->configFactory->getEditable(static::SETTINGS) ->set($config_r . 'words', explode(',', $form_state->getValue('words'))) @@ -129,4 +125,5 @@ public function submitForm(array &$form, FormStateInterface $form_state) { return parent::submitForm($form, $form_state); } -} \ No newline at end of file + +} diff --git a/trpcultivate_phenotypes/src/Form/TripalCultivatePhenotypesWatermarkSettingsForm.php b/trpcultivate_phenotypes/src/Form/TripalCultivatePhenotypesWatermarkSettingsForm.php index ce977ce7..cbc5bdec 100644 --- a/trpcultivate_phenotypes/src/Form/TripalCultivatePhenotypesWatermarkSettingsForm.php +++ b/trpcultivate_phenotypes/src/Form/TripalCultivatePhenotypesWatermarkSettingsForm.php @@ -1,25 +1,61 @@ file_url_generator = $file_url_generator; + $this->service_EntityTypeManager = $service_EntityTypeManager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('file_url_generator'), + $container->get('entity_type.manager') + ); + } + /** * {@inheritdoc} */ @@ -53,12 +89,12 @@ public function buildForm(array $form, FormStateInterface $form_state) { $form['description'] = [ '#markup' => $this->t('Every diagram generated by Tripal Cultivate Phenotypes can be superimposed with personalized logo or text logo to ensure proper credit/attribution and indicate authenticity. - Use Watermark Chart configuration to set watermarking scheme of modules.') + Use Watermark Chart configuration to set watermarking scheme of modules.'), ]; $watermark_options = [ '1' => $this->t('Watermark all charts'), - '0' => $this->t('Do not watermark any charts') + '0' => $this->t('Do not watermark any charts'), ]; $form['charts'] = [ @@ -76,31 +112,32 @@ public function buildForm(array $form, FormStateInterface $form_state) { '#type' => 'container', '#states' => [ 'visible' => [ - ':input[name="charts"]' => array('value' => '1'), - ] - ] + ':input[name="charts"]' => ['value' => '1'], + ], + ], ]; $form['field_wrapper']['preview'] = [ - '#markup' => '

Watermark Image

' + '#markup' => '

Watermark Image

', ]; $form['field_wrapper']['container'] = [ '#type' => 'container', - '#attributes' => ['style' => [ - 'background-color: #EAEAEA; text-align: center; padding: 20px' - ]], + '#attributes' => [ + 'style' => [ + 'background-color: #EAEAEA; text-align: center; padding: 20px', + ], + ], ]; $image = $config['image']; - $file_url = \Drupal::service('file_url_generator'); $preview = (empty($image)) ? $this->t('No watermark image') - : 'watermark'; + : 'watermark'; $form['field_wrapper']['container']['preview'] = [ - '#markup' => $preview + '#markup' => $preview, ]; // This field is required when choosing to watermark image @@ -114,12 +151,11 @@ public function buildForm(array $form, FormStateInterface $form_state) { '#description' => $this->t('Image file format with transparent background enabled [@ext]', ['@ext' => strtoupper(implode(', ', $valid_ext))]), '#upload_validators' => [ - 'file_validate_extensions' => $valid_ext + 'file_validate_extensions' => $valid_ext, ], - '#upload_location' => $source_path + '#upload_location' => $source_path, ]; - return parent::buildForm($form, $form_state); } @@ -149,13 +185,15 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $charts = $form_state->getValue('charts'); $charts = ($charts == 1) ? TRUE : FALSE; - $watermark = null; + $watermark = NULL; if ($charts) { $file = $form_state->getValue('file'); if ($file) { - $file_obj = File::load(reset($file)); + $file_obj = $this->service_EntityTypeManager + ->getStorage('file') + ->load(reset($file)); // Set it permanent used by this module. $file_obj->setPermanent(); @@ -171,7 +209,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { ->set($config_watermark . 'image', $watermark) ->save(); - return parent::submitForm($form, $form_state); } + } diff --git a/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesGenusOntologyService.php b/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesGenusOntologyService.php index 89728e28..afdd8b83 100644 --- a/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesGenusOntologyService.php +++ b/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesGenusOntologyService.php @@ -1,10 +1,5 @@ config = $config_factory->getEditable($module_settings); // Chado database. - $this->chado = $chado; + $this->chado_connection = $chado; // Tripal Logger service. $this->logger = $logger; } /** - * Fetch all genus from chado.organism in the host site and construct a genus ontology - * configuration values described above. Each genus will contain a configuration value - * for trait+unit+method, database and crop ontology. + * Construct an ontology configuration template array for every genus. + * + * For each organism, initialize an empty template array. + * This array will be used by other genus ontology configuration + * methods, ie. methods in this service. + * + * NOTE: There are no actual configuration values being populated here. * * @return array - * Associative array where each element is keyed by genus and configuration values - * for trait, unit, method, database and crop ontology stored in a array as the value. + * Associative array where each element is keyed by genus and configuration + * values for trait, unit, method, database and crop ontology stored in a + * array as the value. * * ie: [genus_a] = [ * trait, @@ -71,19 +89,19 @@ public function defineGenusOntology() { // Fetch genus in host site. $query = "SELECT genus FROM {1:organism} GROUP BY genus ORDER BY genus ASC"; - $result = $this->chado->query($query); + $result = $this->chado_connection->query($query); if ($result) { - foreach($result as $genus) { - // genus-ontology configuration. + foreach ($result as $genus) { + // Create a genus-ontology configuration string identifier. $config_genus = $this->formatGenus($genus->genus); - $genus_ontology[ $config_genus ] = [ + $genus_ontology[$config_genus] = [ 'trait', 'method', 'unit', 'database', - 'crop_ontology' + 'crop_ontology', ]; } } @@ -92,14 +110,18 @@ public function defineGenusOntology() { } /** - * Register a configuration entry and set each genus ontology configuration values to - * a default value of 0 (not set). + * Register a configuration entry. + * + * Uses the template created by self::defineGenusOntology() to set each + * configuration value (e.g. trait, method, unit) to its + * default value (i.e. 0 which indicates not set) for all unique genus + * in the chado.organism table. * - * @return boolean - * True all genus ontology configuration created and set a default value, False on error. + * @return bool + * True if all genus ontology configuration entries were created and set to + * a default value, False on error. */ public function loadGenusOntology() { - $error = 1; // If we haven't defined the genus ontology terms yet, // then do that first. @@ -112,22 +134,24 @@ public function loadGenusOntology() { // Not set. $default_value = 0; - foreach($this->genus_ontology as $genus => $vars) { + foreach ($this->genus_ontology as $genus => $vars) { // Create an array keyed by the genus. // Genus from genus_ontology property has been sanitized // upon definition in the constructor. - $genus_ontology_configvars[ $genus ] = []; + $genus_ontology_configvars[$genus] = []; - // Create configuration vars traits, unit, method, database and crop ontology. - foreach($vars as $var) { - $genus_ontology_configvars[ $genus ][ $var ] = $default_value; + // Create configuration vars traits, unit, method, database and + // crop ontology. + foreach ($vars as $var) { + $genus_ontology_configvars[$genus][$var] = $default_value; } // At this point each genus now has configuration vars and // ready to register a configuration entry. - // configuration ...cvdbon.genus.genus [trait, unit, method, database, crop_ontology] + // configuration ...cvdbon.genus.genus + // [trait, unit, method, database, crop_ontology]. $this->config - ->set($this->sysvar_genus_ontology . '.' . $genus, $genus_ontology_configvars[ $genus ]); + ->set($this->sysvar_genus_ontology . '.' . $genus, $genus_ontology_configvars[$genus]); } $this->config->save(); @@ -136,17 +160,17 @@ public function loadGenusOntology() { } /** - * Remove any formatting from a string and convert space to underscore + * Remove any formatting from a string and convert space to underscore. * - * @param $genus - * String, genus. + * @param string $genus + * Genus name. * * @return string * Genus name where all leading and trailing spaces removed and * in word (multi-word genus) spaces replaced by an underscore. */ public function formatGenus($genus) { - return (empty($genus)) ? null : str_replace(' ', '_', strtolower(trim($genus))); + return (empty($genus)) ? NULL : str_replace(' ', '_', strtolower(trim($genus))); } /** @@ -168,8 +192,8 @@ public function formatGenus($genus) { * ], * ... * - * @return boolean - * True, configuration saved successfully and False on error. + * @return bool + * True if configuration saved successfully and False on error. */ public function saveGenusOntologyConfigValues($config_values) { $error = 0; @@ -184,7 +208,7 @@ public function saveGenusOntologyConfigValues($config_values) { // Make sure genus key exists. $genus_keys = array_keys($this->genus_ontology); - foreach($config_values as $genus => $values) { + foreach ($config_values as $genus => $values) { $genus_key = $this->formatGenus($genus); if (in_array($genus_key, $genus_keys)) { @@ -193,16 +217,16 @@ public function saveGenusOntologyConfigValues($config_values) { // configuration schema definition. $genus_ontology_values = []; - foreach($values as $config_name => $config_value) { - if (in_array($config_name, $this->genus_ontology[ $genus_key ])) { + foreach ($values as $config_name => $config_value) { + if (in_array($config_name, $this->genus_ontology[$genus_key])) { // Save. - $genus_ontology_values[ $config_name ] = $config_value; + $genus_ontology_values[$config_name] = $config_value; } else { // Not expecting this configuration name. $this->logger->error('Error. Failed to save configuration. Unexpected configuration name: ' . $config_name); $error = 1; - break; break; + break 2; } } @@ -233,10 +257,11 @@ public function saveGenusOntologyConfigValues($config_values) { * Get genus ontology configuration values. * * @param string $genus - * Genus + * Genus name. * * @return array - * Associated genus configuration values trait, unit, method, database and crop ontology. + * Associated genus configuration values trait, unit, method, database and + * crop ontology. */ public function getGenusOntologyConfigValues($genus) { $config_values = 0; @@ -269,12 +294,12 @@ public function getGenusOntologyConfigValues($genus) { public function getConfiguredGenusList() { // Fetch all unique genus. $query = "SELECT genus FROM {1:organism} GROUP BY genus ORDER BY genus ASC"; - $result = $this->chado->query($query); + $result = $this->chado_connection->query($query); // Array to hold active genus. $active_genus = []; - foreach($result as $genus) { + foreach ($result as $genus) { $genus = $genus->genus; $genus_key = $this->formatGenus($genus); @@ -289,4 +314,5 @@ public function getConfiguredGenusList() { return $active_genus; } + } diff --git a/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesGenusProjectService.php b/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesGenusProjectService.php index 1366467f..a1a4ef85 100644 --- a/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesGenusProjectService.php +++ b/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesGenusProjectService.php @@ -1,34 +1,41 @@ sysvar_genusontology = $config->get('trpcultivate.phenotypes.ontology.cvdbon'); // Chado database. - $this->chado = $chado; + $this->chado_connection = $chado; // Tripal Logger service. $this->logger = $logger; } - + /** * Assign a genus to an experiment/project. - * + * * @param int $project * Project (project id number) the parameter $genus will be assigned to. * @param string $genus * Genus name/title. - * @param boolean $replace + * @param bool $replace * True to replace existing genus of a project with a different genus. * Default to False. * - * @return boolean + * @return bool * True, genus was set successfully or false on error/fail. */ - function setGenusToProject($project, $genus, $replace = FALSE) { + public function setGenusToProject($project, $genus, $replace = FALSE) { $error = 0; - + if (empty($project) || $project <= 0) { $error = 1; $this->logger->error('Error, Project id is empty string, 0 or not a positive number. Could not replace genus.'); @@ -82,29 +89,36 @@ function setGenusToProject($project, $genus, $replace = FALSE) { $is_active_genus = (in_array($g, array_keys($this->sysvar_genusontology))) ? TRUE : FALSE; if ($is_active_genus) { - $result = $this->chado->query(" - SELECT projectprop_id AS id FROM {1:projectprop} + $result = $this->chado_connection->query(" + SELECT projectprop_id AS id FROM {1:projectprop} WHERE project_id = :project_id AND type_id = :type_id LIMIT 1 ", [':project_id' => $project, ':type_id' => $this->sysvar_genus]); - + $projectprop_id = $result->fetchField(); if ($projectprop_id > 0) { // Has a genus. if ($replace) { // And wishes to replace with another genus. - $this->chado->query(" + $this->chado_connection->query(" UPDATE {1:projectprop} SET value = :new_genus WHERE projectprop_id = :id ", [':new_genus' => $genus, ':id' => $projectprop_id]); } // Do nothing if maintain the same genus. - } + } else { // Not set yet, no record in projectprop. // Create a relationship regardless to replace or not. $sql = "INSERT INTO {1:projectprop} (project_id, type_id, value) VALUES (:project, :config_genus, :genus)"; - $this->chado->query($sql, [':project' => $project, ':config_genus' => $this->sysvar_genus, ':genus' => $genus]); + $this->chado_connection->query( + $sql, + [ + ':project' => $project, + ':config_genus' => $this->sysvar_genus, + ':genus' => $genus, + ], + ); } } else { @@ -118,26 +132,28 @@ function setGenusToProject($project, $genus, $replace = FALSE) { /** * Get genus of an experiment/project. - * + * * @param int $project * Project (project_id number) to search. * * @return array - * Key is genus/organism id number and value is the genus name/title. + * Key is genus/organism id number and value is the genus name/title. */ public function getGenusOfProject($project) { $genus_project = 0; if ($project > 0) { $sysvar_genus = array_keys($this->sysvar_genusontology); - $active_genus = array_map(function($g) { return strtolower(str_replace('_', ' ', $g)); }, $sysvar_genus); - + $active_genus = array_map(function ($g) { + return strtolower(str_replace('_', ' ', $g)); + }, $sysvar_genus); + // Fetch genus paired to a project. If multiple genus have been set prior, // restrict search to genus that are active/configured using this module. - $result = $this->chado->query(" - SELECT organism_id AS id, genus FROM {1:organism} - WHERE genus = (SELECT value::VARCHAR FROM {1:projectprop} - WHERE project_id = :project_id AND type_id = :type_id AND LOWER(value) IN (:active_genus[]) LIMIT 1) + $result = $this->chado_connection->query(" + SELECT organism_id AS id, genus FROM {1:organism} + WHERE genus = (SELECT value::VARCHAR FROM {1:projectprop} + WHERE project_id = :project_id AND type_id = :type_id AND LOWER(value) IN (:active_genus[]) LIMIT 1) LIMIT 1 ", [':project_id' => $project, ':type_id' => $this->sysvar_genus, ':active_genus[]' => $active_genus]); @@ -146,4 +162,5 @@ public function getGenusOfProject($project) { return ($genus_project) ? ['id' => $genus_project->id, 'genus' => $genus_project->genus] : 0; } -} \ No newline at end of file + +} diff --git a/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesTermsService.php b/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesTermsService.php index 35bee75a..e27d082d 100644 --- a/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesTermsService.php +++ b/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesTermsService.php @@ -1,46 +1,58 @@ sysvar_terms = 'trpcultivate.phenotypes.ontology.terms'; @@ -51,14 +63,17 @@ public function __construct(ConfigFactoryInterface $config_factory, TripalLogger // Tripal Logger service. $this->logger = $logger; + // Chado database. + $this->chado_connection = $chado; + // Prepare array of default terms from configuration definition. $this->terms = $this->defineTerms(); } /** * Define terms. + * * Each term set is defined using the array structure below: - * @see config/schema for ontology terms - default_terms * Format: * cv - 1 name * cv - 1 definition @@ -66,7 +81,7 @@ public function __construct(ConfigFactoryInterface $config_factory, TripalLogger * config_map // Maps to which configuration variable. * term - 1 name * term - 1 id - * term - 1 definition + * term - 1 definition. * * config_map * term - 2 name @@ -76,27 +91,28 @@ public function __construct(ConfigFactoryInterface $config_factory, TripalLogger * .... * ... * + * @see config/schema + * * @return array * All configuration entity values keyed by configuration map value. */ public function defineTerms() { - $terms =[]; + $terms = []; - // Fetch all terms in the terms config_entity and prepare an associative array - // where each element is keyed by the configuration map value. + // Fetch all terms in the terms config_entity and prepare an associative + // array where each element is keyed by the configuration map value. $default_terms = $this->config->get('trpcultivate.default_terms.term_set'); - // Terms are not available as configuration values until - // job to install terms has been executed. This value is null - // to start with. + // Terms are not available as configuration values until job to install + // terms has been executed. This value is null to start with. if ($default_terms) { - foreach($default_terms as $i => $cv) { - foreach($cv['terms'] as $term_set) { + foreach ($default_terms as $cv) { + foreach ($cv['terms'] as $term_set) { // Add the cv information of the term. $term_set['cv'] = ['name' => $cv['name'], 'definition' => $cv['definition']]; // Access a term by configuration map value. - // ie: term['experiment_container'] - $terms[ $term_set['config_map'] ] = $term_set; + // ie: term['experiment_container']. + $terms[$term_set['config_map']] = $term_set; } } } @@ -107,24 +123,23 @@ public function defineTerms() { /** * Insert and create term configuration variable. * - * @return boolean + * @return bool * True if all terms were inserted successfully and false otherwise. */ public function loadTerms($schema = NULL) { $error = 0; $terms = $this->terms; - $chado = \Drupal::service('tripal_chado.database'); if ($terms) { // Install terms. - foreach($terms as $config_map => $config_prop) { + foreach ($terms as $config_map => $config_prop) { // Remove cv information. unset($config_prop['cv']); // Remove term field_label text. unset($config_prop['field_label']); - list($idspace, $accession) = explode(':', $config_prop['id']); - $query = $chado->select('1:cvterm', 'cvt') + [$idspace, $accession] = explode(':', $config_prop['id']); + $query = $this->chado_connection->select('1:cvterm', 'cvt') ->fields('cvt', ['cvterm_id']); $query->join('1:dbxref', 'dbx', 'cvt.dbxref_id = dbx.dbxref_id'); $query->join('1:db', 'db', 'dbx.db_id = db.db_id'); @@ -170,22 +185,24 @@ public function loadTerms($schema = NULL) { * * @param string $term_key * The unique identifier for the term of interest. This should be one of: - * data_collector: Data Collector. - * entry: Entry Number/Information. - * genus: Organism. - * location: Location. - * method: Collection Method. - * name: Name/Germplasm line. - * experiment_container: Plot. - * unit_to_method_relationship_type: Related - create relationships (unit - method). - * method_to_trait_relationship_type: Related - create relationships (method - trait). - * experiment_replicate: Planting replicate. - * unit: Unit of measurement. - * experiment_year: Year. - * @see schema/trpcultivate_phenotypes.schema.yml for detailed - * description of each configuration variable name. - * - * @return integer + * - data_collector: Data Collector. + * - entry: Entry Number/Information. + * - genus: Organism. + * - location: Location. + * - name: Name/Germplasm line. + * - experiment_container: Plot. + * - unit_to_method_relationship_type: Related - create relationships + * (unit - method). + * - method_to_trait_relationship_type: Related - create relationships + * (method - trait). + * - experiment_replicate: Planting replicate. + * - unit_type: Unit of measurement. + * - experiment_year: Year. + * - trait_to_synonym_relationship_type: Prefered term. + * + * @see schema/trpcultivate_phenotypes.schema.yml + * + * @return int * The chado cvterm_id for the term associated with that key. * 0 if non-existent configuration name/key. */ @@ -212,11 +229,16 @@ public function getTermId(string $term_key) { * variable name and the value being the value as set in * corresponding form field resolved to id number. * - * ie: $config_values[name] = 1; // Null term, Already resolved to id number. - * // name configuration variable name is set to Null term. + * For example, the following indicates that the chado.cvterm.cvterm_id for + * the 'name' configuration variable is '1'. This resolves to the 'Null' + * cvterm when that cvterm_id is looked up in the cvterm table. * - * @return boolean - * True, configuration saved successfully and False on error. + * @code + * $config_values['name'] = 1; + * @endcode + * + * @return bool + * True if configuration saved successfully and False on error. */ public function saveTermConfigValues($config_values) { $error = 0; @@ -224,7 +246,7 @@ public function saveTermConfigValues($config_values) { if (!empty($config_values) && is_array($config_values) && $this->terms) { $term_keys = array_keys($this->terms); - foreach($config_values as $config => $value) { + foreach ($config_values as $config => $value) { // Make sure config name exists before saving a value. if (in_array($config, $term_keys)) { $this->config @@ -248,4 +270,5 @@ public function saveTermConfigValues($config_values) { return ($error > 0) ? FALSE : TRUE; } + } diff --git a/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesTraitsService.php b/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesTraitsService.php index f3d64e76..d702902e 100644 --- a/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesTraitsService.php +++ b/trpcultivate_phenotypes/src/Service/TripalCultivatePhenotypesTraitsService.php @@ -1,36 +1,51 @@ NULL, 'unit_to_method_relationship_type' => NULL, @@ -41,42 +56,46 @@ class TripalCultivatePhenotypesTraitsService { /** * Constructor. */ - public function __construct(TripalCultivatePhenotypesGenusOntologyService $genus_ontology, TripalCultivatePhenotypesTermsService $terms, ChadoConnection $chado) { + public function __construct( + TripalCultivatePhenotypesGenusOntologyService $genus_ontology, + TripalCultivatePhenotypesTermsService $terms, + ChadoConnection $chado, + ) { // Genus ontology service. - $this->service_genus_ontology = $genus_ontology; + $this->service_PhenoGenusOntology = $genus_ontology; // Terms service. - $this->service_terms = $terms; + $this->service_PhenoTerms = $terms; // Chado connection. - $this->chado = $chado; + $this->chado_connection = $chado; // Terms configurations. // Terms focused on adding traits, required by this service. - foreach($this->terms as $config_key => $value) { - $this->terms[ $config_key ] = $this->service_terms->getTermId($config_key); + foreach ($this->terms as $config_key => $value) { + $this->terms[$config_key] = $this->service_PhenoTerms->getTermId($config_key); } } /** - * Set the genus configuration values to which all - * methods will use to restrict any trait data operations. + * Set the genus configuration values. + * + * Configuration values will be use to restrict any trait data operations. * * @param string $genus * A specific genus to reference in genus ontology configurations. * - * @return void - * * @throws \Exception * And exception is thrown by this method if * - the terms used by this module are not configured * - the genus is not configured for use with phenotypes - * - the genus does not exist in the chado organism table in the default chado instance. + * - the genus does not exist in the chado organism table in the default + * chado instance. */ public function setTraitGenus(string $genus) { - // For this setter to work both Genus and Terms configuration must be configured. - // Term configuration: + // For this setter to work both Genus and Terms configuration must be + // configured. $not_set = []; - foreach($this->terms as $config_key => $value) { - if ($this->terms[ $config_key ] <= 0) { + foreach ($this->terms as $config_key => $value) { + if ($this->terms[$config_key] <= 0) { // A term was not configured. $not_set[] = $config_key; } @@ -84,54 +103,56 @@ public function setTraitGenus(string $genus) { if ($not_set) { $terms_not_set = implode(', ', $not_set); - throw new \Exception(t('Term(s) [@term] used to create trait asset relationships was not configured. - To configure terms, go to @url and set the controlled vocabulary associated with the term.', - ['@term' => $terms_not_set, '@url' => Url::fromRoute('trpcultivate_phenotypes.settings_ontology')->toString()] - )); + throw new \Exception('Term(s) ' . $terms_not_set . ' used to create trait + asset relationships was not configured. To configure terms, go to' . + Url::fromRoute('trpcultivate_phenotypes.settings_ontology')->toString() . + 'and set the controlled vocabulary associated with the term.'); } // Genus configuration: // Fetch all configured genus (active genus). - $active_genus = $this->service_genus_ontology->getConfiguredGenusList(); + $active_genus = $this->service_PhenoGenusOntology->getConfiguredGenusList(); if ($active_genus && in_array($genus, $active_genus)) { - $genus_config = $this->service_genus_ontology->getGenusOntologyConfigValues($genus); + $genus_config = $this->service_PhenoGenusOntology->getGenusOntologyConfigValues($genus); // Resolve each configuration entry id number to names. $cv_sql = "SELECT name FROM {1:cv} WHERE cv_id = :id"; $db_sql = "SELECT name FROM {1:db} WHERE db_id = :id"; - foreach($genus_config as $config => $value) { + foreach ($genus_config as $config => $value) { if ($value > 0) { // Ontology might be set to 0 - as it is optional in the config page. // Reference only values that have been set. if ($config == 'database') { // DB configuration. - $name = $this->chado->query($db_sql, [':id' => $value]) + $name = $this->chado_connection->query($db_sql, [':id' => $value]) ->fetchField(); } else { // CV configuration. // Configurations: traits, method, unit and crop_ontology. - $name = $this->chado->query($cv_sql, [':id' => $value]) + $name = $this->chado_connection->query($cv_sql, [':id' => $value]) ->fetchField(); } if ($name) { - $this->config[ $config ] = ['id' => $value, 'name' => $name]; + $this->config[$config] = ['id' => $value, 'name' => $name]; } else { - $schema = $this->chado->getSchemaName(); + $schema = $this->chado_connection->getSchemaName(); $table = ($config == 'database') ? $schema . '.db' : $schema . '.cv'; - throw new \Exception(t('We were unable to retrieve the name for the Genus @type in the @table where the primary key is @id.', - ['@type' => $config, '@id' => $value, '@table' => $table])); + throw new \Exception('We were unable to retrieve the name for the Genus ' . + $config . ' in the ' . $table . ' where the primary key is ' . $value); } } } } else { - throw new \Exception(t('The genus "@genus" was not configured for use with Tripal Cultivate Phenotypes. To configure this genus, go to @url and set the controlled vocabularies associated with this genus.', - ['@genus' => $genus, '@url' => Url::fromRoute('trpcultivate_phenotypes.settings_ontology')->toString()])); + throw new \Exception('The genus "' . $genus . '" was not configured for + use with Tripal Cultivate Phenotypes. To configure this genus, go to ' . + Url::fromRoute('trpcultivate_phenotypes.settings_ontology')->toString() . + ' and set the controlled vocabularies associated with this genus.'); } } @@ -141,20 +162,21 @@ public function setTraitGenus(string $genus) { * @param array $trait * Trait added to this module has the following data keys: * - Trait Name: the name of the trait (e.g. Plant Height). - * - Trait Description: the description of the trait (e.g. the height of the plant from the - * ground to it's tallest point without stretching the plant.) - * - Method Short Name: a short name for the method (e.g. Average of 5 plants) - * - Collection Method: a description of the method used to collect the phenotypic data - * (e.g. measured 5 plants from the plot and then averaged them.) - * - Unit: the full word describing the unit used in the method (e.g. centimeters) + * - Trait Description: the description of the trait (eg. The height of the + * plant from ground to it's tallest point without stretching the plant.) + * - Method Short Name: a short name of the method (eg. Average of 5 plants) + * - Collection Method: a description of the method used to collect the + * phenotypic data (eg. Measure 5 plants from the plot and average them.) + * - Unit: the full word describing the unit used in the method + * (e.g. centimeters) * - Type: Quantitative or Qualitative. * @param string $schema * The name of the schema that the terms are expected to live in. This is * passed to the legacy chado_insert_cvterm() and if NULL, the default * chado instance will be used. * - * @return - * An array with the following keys where each value is the id of new cvterm: + * @return array + * An array with the following keys where each value is the id of new cvterm * trait, method, unit. * * @throws \Exception @@ -168,70 +190,69 @@ public function setTraitGenus(string $genus) { * @dependencies * getPhenoCvterm(), getMethodUnitDataType(). */ - public function insertTrait(array $trait, string $schema = NULL) { + public function insertTrait(array $trait, ?string $schema = NULL) { // Configuration settings of the genus. $genus_config = $this->config; if (!$genus_config) { // Genus not set. - throw new \Exception(t('No genus has been set. See setting a genus in the Traits Service and make sure to - use a configured genus. To configure a genus or see all configured genus, go to @url.', - ['@url' => Url::fromRoute('trpcultivate_phenotypes.settings_ontology')->toString()] - )); + throw new \Exception('No genus has been set. See setting a genus in the + Traits Service and make sure to use a configured genus. To configure a + genus or see all configured genus, go to ' . + Url::fromRoute('trpcultivate_phenotypes.settings_ontology')->toString()); } // TRAIT, METHOD and UNIT data array. $arr_trait = [ - 'trait' => [ - 'name' => $trait['Trait Name'], + 'trait' => [ + 'name' => $trait['Trait Name'], 'description' => $trait['Trait Description'], ], 'method' => [ 'name' => $trait['Method Short Name'], 'description' => $trait['Collection Method'], ], - 'unit' => [ + 'unit' => [ 'name' => $trait['Unit'], 'description' => $trait['Unit'], - ] + ], ]; // Create trait: Trait, Method and Unit. - foreach($arr_trait as $type => $values) { + foreach ($arr_trait as $type => $values) { // Inspect cvterm to see if the trait asset already existed. $trait_asset_rec = $this->getPhenoCvterm($values['name'], $type); if ($trait_asset_rec) { // Trait asset found, reference the record and re-use. - $arr_trait[ $type ]['id'] = $trait_asset_rec->cvterm_id; + $arr_trait[$type]['id'] = $trait_asset_rec->cvterm_id; } else { // A new trait asset, create a record. $rec = [ 'id' => $genus_config['database']['name'] . ':' . $values['name'], 'name' => $values['name'], - 'cv_name' => $genus_config[ $type ]['name'], - 'definition' => $values['description'] + 'cv_name' => $genus_config[$type]['name'], + 'definition' => $values['description'], ]; $ins = chado_insert_cvterm($rec, [], $schema); if (!$ins) { // Could not insert cvterm. - throw new \Exception(t('A database error occurred while inserting a term. Failed to insert term @type : @term.', - ['@type' => $type, '@term' => $values['name']] - )); + throw new \Exception('A database error occurred while inserting a term. + Failed to insert term ' . $type . ' : ' . $term); } - $arr_trait[ $type ]['id'] = $ins->cvterm_id; + $arr_trait[$type]['id'] = $ins->cvterm_id; } } // RELATIONSHIPS: trait-method and method-unit. $arr_rel = [ 'method-trait' => $this->terms['method_to_trait_relationship_type'], - 'method-unit' => $this->terms['unit_to_method_relationship_type'] + 'method-unit' => $this->terms['unit_to_method_relationship_type'], ]; - foreach($arr_rel as $type => $rel) { + foreach ($arr_rel as $type => $rel) { // Check if relationship exists. if ($type == 'method-trait') { $subject = $arr_trait['trait']['id']; @@ -250,7 +271,7 @@ public function insertTrait(array $trait, string $schema = NULL) { $exists = FALSE; if (is_array($related_terms)) { - foreach($related_terms as $rec) { + foreach ($related_terms as $rec) { if ($rec->cvterm_id == $object) { $exists = TRUE; break; @@ -259,19 +280,18 @@ public function insertTrait(array $trait, string $schema = NULL) { } if (!$exists) { - $ins_rel = $this->chado->insert('1:cvterm_relationship') + $ins_rel = $this->chado_connection->insert('1:cvterm_relationship') ->fields([ 'subject_id' => $subject, 'type_id' => $rel, - 'object_id' => $object + 'object_id' => $object, ]) ->execute(); if (!$ins_rel) { - throw new \Exception(t('A database error occurred while inserting a term relationship. - Failed to create term relationship @type : subject id - @subject object id - @object.', - ['@type' => $type, '@subject' => $subject, '@object' => $object] - )); + throw new \Exception('A database error occurred while inserting a term relationship. + Failed to create term relationship ' . $type . ' : subject id - ' . + $subject . ' object id - ' . $object); } } } @@ -279,18 +299,17 @@ public function insertTrait(array $trait, string $schema = NULL) { // UNIT DATA TYPE: $data_type = $this->getMethodUnitDataType($arr_trait['unit']['id']); if (!$data_type) { - $ins_type = $this->chado->insert('1:cvtermprop') + $ins_type = $this->chado_connection->insert('1:cvtermprop') ->fields([ 'cvterm_id' => $arr_trait['unit']['id'], 'type_id' => $this->terms['unit_type'], - 'value' => $trait['Type'] + 'value' => $trait['Type'], ]) ->execute(); if (!$ins_type) { - throw new \Exception(t('A database error occurred while inserting a unit data type. Failed to insert unit data type @unit : @data_type.', - ['@unit' => $type, '@data_type' => $trait['Unit']] - )); + throw new \Exception('A database error occurred while inserting a unit + data type. Failed to insert unit data type ' . $type . ' : ' . $trait['Unit']); } } @@ -299,7 +318,7 @@ public function insertTrait(array $trait, string $schema = NULL) { return [ 'trait' => $arr_trait['trait']['id'], 'method' => $arr_trait['method']['id'], - 'unit' => $arr_trait['unit']['id'] + 'unit' => $arr_trait['unit']['id'], ]; } } @@ -320,14 +339,16 @@ public function insertTrait(array $trait, string $schema = NULL) { * to the trait parameter. * - the genus/terms are not configured * - the key is not either a positive integer or a non-empty string. - * - more than one cvterm was returned + * - more than one cvterm was returned. * * @dependencies * getPhenoCvterm() */ public function getTrait($trait) { - // Since the trait is simply a cvterm, we can use our helper method to retrieve it. + // Since the trait is simply a cvterm, we can use our helper method to + // retrieve it. $trait_rec = $this->getPhenoCvterm($trait, 'trait'); + return $trait_rec; } @@ -340,15 +361,16 @@ public function getTrait($trait) { * * @return array * All matching records (cvterm object) in an array. - * Empty array if there are no methods for this trait or if the trait doesn't exist. - * If there is only one result (unit) returned access the value using index 0. + * Empty array if there are no methods for this trait or if the trait + * doesn't exist. If there is only one result (unit) returned access the + * value using index 0. * * @throws \Exception * An exception is thrown by getPhenoCvterm() if any of the following apply * to the trait parameter. * - the genus/terms are not configured * - the key is not either a positive integer or a non-empty string. - * - more than one cvterm was returned + * - more than one cvterm was returned. * * @dependencies * getPhenoCvterm() @@ -356,25 +378,27 @@ public function getTrait($trait) { public function getTraitMethod($trait) { $trait_rec = $this->getPhenoCvterm($trait, 'trait'); if (!$trait_rec) { + // Trait was not found. return []; } - // Inspect the relationship table where the trait has a trait - method relationship. + // Inspect the relationship table where the trait has a + // trait - method relationship. $sql = "SELECT object_id AS id FROM {1:cvterm_relationship} WHERE subject_id = :s_id AND type_id = :t_id"; $args = [ ':s_id' => (int) $trait_rec->cvterm_id, - ':t_id' => $this->terms['method_to_trait_relationship_type'] + ':t_id' => $this->terms['method_to_trait_relationship_type'], ]; - $method_ids = $this->chado->query($sql, $args) + $method_ids = $this->chado_connection->query($sql, $args) ->fetchCol(); $methods = []; if (count($method_ids) > 0) { // Has methods. - $methods = $this->chado->query( + $methods = $this->chado_connection->query( "SELECT * FROM {1:cvterm} WHERE cvterm_id IN (:ids[])", [':ids[]' => array_values($method_ids)] ) @@ -393,15 +417,16 @@ public function getTraitMethod($trait) { * * @return array * All matching records (cvterm object) in an array. - * Empty array if there are no units for this method or if the method doesn't exist. - * If there is only one result (unit) returned access the value using index 0. + * Empty array if there are no units for this method or if the method + * doesn't exist. If there is only one result (unit) returned access the + * value using index 0. * * @throws \Exception * An exception is thrown by getPhenoCvterm() if any of the following apply * to the method parameter. * - the genus/terms are not configured * - the key is not either a positive integer or a non-empty string. - * - more than one cvterm was returned + * - more than one cvterm was returned. * * @dependencies * getPhenoCvterm() @@ -413,21 +438,22 @@ public function getMethodUnit($method) { return []; } - // Inspect the relationship table where method has a method - unit relationship. + // Inspect the relationship table where method has + // a method - unit relationship. $sql = "SELECT object_id AS id FROM {1:cvterm_relationship} WHERE subject_id = :s_id AND type_id = :t_id"; $args = [ ':s_id' => (int) $method_rec->cvterm_id, - ':t_id' => $this->terms['unit_to_method_relationship_type'] + ':t_id' => $this->terms['unit_to_method_relationship_type'], ]; - $unit_ids = $this->chado->query($sql, $args) + $unit_ids = $this->chado_connection->query($sql, $args) ->fetchCol(); $units = []; if (count($unit_ids) > 0) { // Has units. - $units = $this->chado->query( + $units = $this->chado_connection->query( "SELECT * FROM {1:cvterm} WHERE cvterm_id IN (:ids[])", [':ids[]' => array_values($unit_ids)] ) @@ -449,12 +475,12 @@ public function getMethodUnit($method) { * NULL if the unit doesn't exist or there was no data type set for it. * * @throws \Exception - * This method throws an exception if multiple data types are set for the given unit. - * An exception is thrown by getPhenoCvterm() if any of the following apply - * to the unit parameter. + * This method throws an exception if multiple data types are set for the + * given unit. An exception is thrown by getPhenoCvterm() if any of the + * following apply to the unit parameter. * - the genus/terms are not configured * - the key is not either a positive integer or a non-empty string. - * - more than one cvterm was returned + * - more than one cvterm was returned. * * @dependencies * getPhenoCvterm() @@ -466,23 +492,23 @@ public function getMethodUnitDataType($unit) { return NULL; } - // Inspect the relationship table where unit has a unit - data type relationship. + // Inspect the relationship table where unit has + // a unit - data type relationship. $sql = "SELECT value FROM {1:cvtermprop} WHERE cvterm_id = :c_id AND type_id = :t_id"; $args = [ ':c_id' => $unit_rec->cvterm_id, - ':t_id' => $this->terms['unit_type'] + ':t_id' => $this->terms['unit_type'], ]; - $data_type = $this->chado->query($sql, $args) + $data_type = $this->chado_connection->query($sql, $args) ->fetchCol(); if (count($data_type) > 1) { // Unit appears to have multiple data types. - throw new \Exception(t('A multiple data type error occurred while retrieving a unit data type. - Failed to retrieve data type for unit : @unit in cv : @cv. Multiple data types found for the same unit.', - ['@unit' => $unit, '@cv' => $genus_config['unit']['name']] - )); + throw new \Exception('A multiple data type error occurred while retrieving + a unit data type. Failed to retrieve data type for unit : ' . $unit . ' in cv : ' . + $genus_config['unit']['name'] . '. Multiple data types found for the same unit.'); } return ($data_type) ? reset($data_type) : NULL; @@ -492,15 +518,18 @@ public function getMethodUnitDataType($unit) { * Get trait, method and unit combination. * * @param string|int $trait - * A string value is the trait name, whereas an integer value is the trait id number. + * A string value is the trait name, whereas an integer value is the + * trait id number. * @param string|int $method - * A string value is the trait method short name, whereas an integer value is the method id number. + * A string value is the trait method short name, whereas an integer + * value is the method id number. * @param string|int $unit - * A string value is the method unit name, whereas an integer value is the unit id number. + * A string value is the method unit name, whereas an integer value is + * the unit id number. * * @return array - * An associative array where the keys are trait, method and unit and the values - * are the cvterm records for each key. + * An associative array where the keys are trait, method and unit and the + * values are the cvterm records for each key. * NULL if any one of trait, method or unit did not return any record. * * @throws \Exception @@ -508,7 +537,7 @@ public function getMethodUnitDataType($unit) { * to the trait, method or unit parameters. * - the genus/terms are not configured * - the key is not either a positive integer or a non-empty string. - * - more than one cvterm was returned + * - more than one cvterm was returned. * * @dependencies * getPhenoCvterm(), getMethodUnitDataType(). @@ -540,7 +569,7 @@ public function getTraitMethodUnitCombo(string|int $trait, string|int $method, s return [ 'trait' => $trait_rec, 'method' => $method_rec, - 'unit' => $unit_rec + 'unit' => $unit_rec, ]; } @@ -562,51 +591,47 @@ public function getTraitMethodUnitCombo(string|int $trait, string|int $method, s * - the genus/terms are not configured * - the type is not one of 'trait', 'method' or 'unit' * - the key is not either a positive integer or a non-empty string. - * - more than one cvterm was returned + * - more than one cvterm was returned. */ protected function getPhenoCvterm($key, $type = 'trait') { // Configuration check. $genus_config = $this->config; if (!$genus_config) { // Genus not set. - throw new \Exception(t('No genus has been set. See setting a genus in the Traits Service and make sure to - use a configured genus. To configure a genus or see all configured genus, go to @url.', - ['@url' => Url::fromRoute('trpcultivate_phenotypes.settings_ontology')->toString()] - )); + throw new \Exception('No genus has been set. See setting a genus in the + Traits Service and make sure to use a configured genus. To configure a + genus or see all configured genus, go to ' . + Url::fromRoute('trpcultivate_phenotypes.settings_ontology')->toString()); } // Parameter check. if (!in_array($type, ['trait', 'method', 'unit'])) { // Not a valid parameter asset type value.. - throw new \Exception(t('Not a valid trait asset type value provided. Trait asset getter expects type to be the - string trait, method or unit.' - )); + throw new \Exception('Not a valid trait asset type value provided. Trait + asset getter expects type to be the string trait, method or unit.'); } if (empty($key) || (is_numeric($key) && (int) $key < 0) || (!is_numeric($key) && !is_string($key))) { // Not a valid asset key value (0, negative values or an empty string). - throw new \Exception(t('Not a valid @type key value provided. The trait asset getter expects a string name or - an integer id key value.', ['@type' => $type] - )); + throw new \Exception('Not a valid ' . $type . ' key value provided. + The trait asset getter expects a string name or an integer id key value.'); } - // If we are given an integer then assume it is the cvterm_id... $asset_rec = NULL; if (is_numeric($key)) { // Asset parameter key is the id number. - $asset_rec = $this->chado->query( + $asset_rec = $this->chado_connection->query( "SELECT * FROM {1:cvterm} WHERE cvterm_id = :value", [':value' => (int) $key] ) ->fetchAll(); - if ($asset_rec && (int) $asset_rec[0]->cv_id != $genus_config[ $type ]['id']) { + if ($asset_rec && (int) $asset_rec[0]->cv_id != $genus_config[$type]['id']) { // The id number seems to be of a trait asset that is outside of // the cv: asset type (trait, method or unit) the genus was configured. - throw new \Exception(t('The requested trait asset @type : id @key CV value does not match the CV the genus was configured.', - ['@type' => $type, '@key' => $key] - )); + throw new \Exception('The requested trait asset ' . $type . ' : id ' . $key . + ' CV value does not match the CV the genus was configured.'); } } @@ -614,27 +639,28 @@ protected function getPhenoCvterm($key, $type = 'trait') { // then assume we are given the term name... if (!$asset_rec) { // Asses parameter key is the name. - $asset_rec = $this->chado->query( + $asset_rec = $this->chado_connection->query( "SELECT * FROM {1:cvterm} WHERE name = :value AND cv_id = :cv", - [':value' => $key, ':cv' => $genus_config[ $type ]['id']] + [':value' => $key, ':cv' => $genus_config[$type]['id']] ) ->fetchAll(); if ($asset_rec && count($asset_rec) > 1) { - // Trait asset name requested appears to have copies in the cv: asset type (trait, method or unit) the genus was configured. + // Trait asset name requested appears to have copies in the cv: asset + // type (trait, method or unit) the genus was configured. // Log error for admin to resolve. - throw new \Exception(t('A duplicate term error occurred while retrieving a trait asset. - Failed to retrieve @type : @key in cv : @cv. Multiple copies of the same term found in the CV', - ['@type' => $type, '@key' => $key, '@cv' => $genus_config[ $type ]['name']] - )); + throw new \Exception('A duplicate term error occurred while retrieving a trait asset. + Failed to retrieve $type : $key in cv : ' . $genus_config[$type]['name'] . + '. Multiple copies of the same term found in the CV'); } } - if(!$asset_rec) { - // cvterm was not found. + if (!$asset_rec) { + // Cvterm was not found. return NULL; } return reset($asset_rec); } + } diff --git a/trpcultivate_phenotypes/tests/src/Functional/ConfigOntologyTermsTest.php b/trpcultivate_phenotypes/tests/src/Functional/ConfigOntologyTermsTest.php index 48a22d7b..dabb6e8c 100644 --- a/trpcultivate_phenotypes/tests/src/Functional/ConfigOntologyTermsTest.php +++ b/trpcultivate_phenotypes/tests/src/Functional/ConfigOntologyTermsTest.php @@ -1,24 +1,33 @@ container->set($service_name, NULL); @@ -72,7 +81,7 @@ public function testForm() { // Setup admin user account. $this->admin_user = $this->drupalCreateUser([ 'administer site configuration', - 'administer tripal' + 'administer tripal', ]); // Ensure we see all logging in tests. @@ -89,11 +98,11 @@ public function testForm() { $session->pageTextContains('Warning message'); // Tripal Jobs to create/insert terms and setup genus ontology configuration - // are created on install of tripalcultivate_phenotypes. The job may execute or not - // but this block will create them manually. + // are created on install of tripalcultivate_phenotypes. The job may execute + // or not but this block will create them manually. $test_insert_genus = [ 'Lens', - 'Cicer' + 'Cicer', ]; $this->chado_connection->insert('1:organism') @@ -101,17 +110,17 @@ public function testForm() { ->values([ 'genus' => $test_insert_genus[0], 'species' => 'culinaris', - 'type_id' => 1 + 'type_id' => 1, ]) ->values([ 'genus' => $test_insert_genus[0], 'species' => 'samegenus', - 'type_id' => 1 + 'type_id' => 1, ]) ->values([ 'genus' => $test_insert_genus[1], 'species' => 'arietinum', - 'type_id' => 1 + 'type_id' => 1, ]) ->execute(); @@ -149,22 +158,23 @@ public function testForm() { // Test setting the same cv value for trait, method and unit in the same // genus will trigger an error. $j = 0; - foreach($genus_ontology as $genus => $vars) { - foreach($vars as $i => $config) { + foreach ($genus_ontology as $genus => $vars) { + foreach ($vars as $i => $config) { $fld_name = $genus . '_' . $config; - // Test if each genus has a trait, unit, method, db and crop ontology field. + // Test if each genus has a trait, unit, method, db and crop ontology + // field. $session->fieldExists($fld_name); if ($config == 'database') { - $set_val = $test_db_id[ $j ]; + $set_val = $test_db_id[$j]; $j++; } else { // Same cv. - $set_val = $test_cv_id[ 0 ]; + $set_val = $test_cv_id[0]; } - $values_genusontology[ $fld_name ] = $set_val; + $values_genusontology[$fld_name] = $set_val; } } @@ -173,21 +183,22 @@ public function testForm() { $session->pageTextContains('Error: Controlled Vocabulary (CV) value for Trait, Method and Unit must have unique values'); $j = 0; - foreach($genus_ontology as $genus => $vars) { - foreach($vars as $i => $config) { + foreach ($genus_ontology as $genus => $vars) { + foreach ($vars as $i => $config) { $fld_name = $genus . '_' . $config; - // Test if each genus has a trait, unit, method, db and crop ontology field. + // Test if each genus has a trait, unit, method, db and crop ontology + // field. $session->fieldExists($fld_name); if ($config == 'database') { - $set_val = $test_db_id[ $j ]; + $set_val = $test_db_id[$j]; $j++; } else { - $set_val = $test_cv_id[ $i ]; + $set_val = $test_cv_id[$i]; } - $values_genusontology[ $fld_name ] = $set_val; + $values_genusontology[$fld_name] = $set_val; } } @@ -196,16 +207,16 @@ public function testForm() { $session->pageTextContains('The configuration options have been saved.'); $j = 0; - foreach($genus_ontology as $genus => $vars) { - foreach($vars as $i => $config) { + foreach ($genus_ontology as $genus => $vars) { + foreach ($vars as $i => $config) { $fld_name = $genus . '_' . $config; if ($config == 'database') { - $set_val = $test_db_id[ $j ]; + $set_val = $test_db_id[$j]; $j++; } else { - $set_val = $test_cv_id[ $i ]; + $set_val = $test_cv_id[$i]; } $session->fieldValueEquals($fld_name, $set_val); @@ -236,11 +247,11 @@ public function testForm() { $values_terms = []; $i = 0; - foreach($terms as $config => $prop) { + foreach ($terms as $config => $prop) { // Test each term has an autocomplete field. $session->fieldExists($config); - $values_terms[ $config ] = $test_cvterms[ $i ]; + $values_terms[$config] = $test_cvterms[$i]; $i++; } @@ -249,9 +260,10 @@ public function testForm() { $session->pageTextContains('The configuration options have been saved.'); $i = 0; - foreach($terms as $config => $prop) { - $session->fieldValueEquals($config, $test_cvterms[ $i ]); + foreach ($terms as $config => $prop) { + $session->fieldValueEquals($config, $test_cvterms[$i]); $i++; } } + } diff --git a/trpcultivate_phenotypes/tests/src/Functional/ConfigRRulesTest.php b/trpcultivate_phenotypes/tests/src/Functional/ConfigRRulesTest.php index b041c662..b2006f22 100644 --- a/trpcultivate_phenotypes/tests/src/Functional/ConfigRRulesTest.php +++ b/trpcultivate_phenotypes/tests/src/Functional/ConfigRRulesTest.php @@ -1,29 +1,34 @@ admin_user = $this->drupalCreateUser([ 'administer site configuration', - 'administer tripal' + 'administer tripal', ]); // Login admin user. @@ -59,11 +64,11 @@ public function testForm() { // Update configuration settings. // Updating R rules by appending ok to words rule, # sign to characters rule - // and ok = okay match and replace rule + // and ok = okay match and replace rule. $update_r_rules = [ - 'words' => implode(',', $r_rules[ $config_r . 'words' ]) . ',ok', - 'chars' => implode(',', $r_rules[ $config_r . 'chars' ]) . ',#', - 'replace' => implode(',', $r_rules[ $config_r . 'replace' ]) . ',ok = okay', + 'words' => implode(',', $r_rules[$config_r . 'words']) . ',ok', + 'chars' => implode(',', $r_rules[$config_r . 'chars']) . ',#', + 'replace' => implode(',', $r_rules[$config_r . 'replace']) . ',ok = okay', ]; // Access R rules configuration page. @@ -75,20 +80,21 @@ public function testForm() { // Fields and default value. $session->fieldExists('words'); - $session->fieldValueEquals('words', implode(',', $r_rules[ $config_r. 'words' ])); + $session->fieldValueEquals('words', implode(',', $r_rules[$config_r . 'words'])); $session->fieldExists('chars'); - $session->fieldValueEquals('chars', implode(',', $r_rules[ $config_r . 'chars' ])); + $session->fieldValueEquals('chars', implode(',', $r_rules[$config_r . 'chars'])); $session->fieldExists('replace'); - $session->fieldValueEquals('replace', implode(',', $r_rules[ $config_r . 'replace' ])); + $session->fieldValueEquals('replace', implode(',', $r_rules[$config_r . 'replace'])); // Update default values. $this->submitForm($update_r_rules, 'Save configuration'); // Saved. $session->pageTextContains('The configuration options have been saved.'); - // Values reflect the updated configuration + // Values reflect the updated configuration. $session->fieldValueEquals('words', $update_r_rules['words']); $session->fieldValueEquals('chars', $update_r_rules['chars']); $session->fieldValueEquals('replace', $update_r_rules['replace']); } + } diff --git a/trpcultivate_phenotypes/tests/src/Functional/ConfigWatermarkTest.php b/trpcultivate_phenotypes/tests/src/Functional/ConfigWatermarkTest.php index 10fd27b4..a602df6f 100644 --- a/trpcultivate_phenotypes/tests/src/Functional/ConfigWatermarkTest.php +++ b/trpcultivate_phenotypes/tests/src/Functional/ConfigWatermarkTest.php @@ -1,35 +1,35 @@ drupalCreateUser([ 'administer site configuration', - 'administer tripal' + 'administer tripal', ]); // Login admin user. @@ -67,21 +66,22 @@ public function testForm() { $session->statusCodeEquals(200); $session->pageTextContains('Configure Tripal Cultivate Phenotypes: Watermark Chart'); + // Fields and default value. + // Field option to watermark which chart is default to 0 - Do not watermark. + $session->fieldExists('charts'); + $session->fieldValueEquals('charts', '0'); + + // Watermark image file field is default to empty string. + $session->fieldExists('files[file]'); + $session->elementTextContains('css', '#edit-file-upload', ''); + // Update configuration settings. // Do not watermark any charts. $update_watermark = [ 'charts' => '0', - // 'file' => '' test could not detect file field. ?? + 'files[file]' => '', ]; - // Fields and default value. - $session->fieldExists('charts'); - $session->fieldValueEquals('charts', '0'); - - // Could not seem to find this field in the form. - // $session->fieldExists('file'); - // $session->fieldValueEquals('file', ''); - // Submit form. $this->submitForm($update_watermark, 'Save configuration'); @@ -93,4 +93,5 @@ public function testForm() { $this->drupalLogout(); } + } diff --git a/trpcultivate_phenotypes/tests/src/Functional/InstallTest.php b/trpcultivate_phenotypes/tests/src/Functional/InstallTest.php index 2b2e35c6..c3cff215 100644 --- a/trpcultivate_phenotypes/tests/src/Functional/InstallTest.php +++ b/trpcultivate_phenotypes/tests/src/Functional/InstallTest.php @@ -1,6 +1,8 @@ drupalGet('admin/modules'); $status_code = $session->getStatusCode(); $this->assertEquals(200, $status_code, "The module install page should be able to load $context."); - $this->assertSession()->pageTextContains( self::$module_name ); + $this->assertSession()->pageTextContains(self::$module_name); } /** @@ -94,7 +109,7 @@ public function testHelp() { // Call the hook to ensure it is returning text. $name = 'help.page.' . $this::$module_machinename; - $match = $this->createStub(\Drupal\Core\Routing\RouteMatch::class); + $match = $this->createStub(RouteMatch::class); $hook_name = self::$module_machinename . '_help'; $output = $hook_name($name, $match); $this->assertNotEmpty($output, "The help hook should return output $context."); @@ -110,4 +125,5 @@ public function testHelp() { $this->assertEquals(200, $status_code, "The module help page should be able to load $context."); $this->assertSession()->pageTextContains($some_extected_text); } + } diff --git a/trpcultivate_phenotypes/tests/src/Kernel/Forms/ConfigWatermarkFormTest.php b/trpcultivate_phenotypes/tests/src/Kernel/Forms/ConfigWatermarkFormTest.php new file mode 100644 index 00000000..59aee5e7 --- /dev/null +++ b/trpcultivate_phenotypes/tests/src/Kernel/Forms/ConfigWatermarkFormTest.php @@ -0,0 +1,183 @@ +set('is_a_test_environment', TRUE); + + // Install configurations. + $this->installConfig(['system', 'trpcultivate_phenotypes']); + $this->installEntitySchema('file'); + + $container = \Drupal::getContainer(); + + // Watermark form controller instance. + $this->watermark_form = new TripalCultivatePhenotypesWatermarkSettingsForm( + $container->get('file_url_generator'), + $container->get('entity_type.manager') + ); + + $this->config = $container->get('config.factory'); + } + + /** + * Test watermark form id matches expected value. + */ + public function testFormId() { + $form_id = $this->watermark_form->getFormId(); + + // Form id set matches. + $this->assertEquals( + 'trpcultivate_phenotypes_watermark_settings_form', + $form_id, + 'The form id returned by getFormId() does not match expected form id value.' + ); + } + + /** + * Test buildForm() method. + */ + public function testBuildForm() { + $form = []; + $form_state = new FormState(); + + $config_form = $this->watermark_form->buildForm($form, $form_state); + + // Form theme is system configuration type. + $this->assertEquals( + 'system_config_form', + $config_form['#theme'], + 'The theme of the form generated by buildForm() method does not match expected theme.' + ); + + // Form has radio button field. + $this->assertEquals( + 'radios', + $config_form['charts']['#type'], + 'The form generated by buildForm() method is missing a form field of type radio button.', + ); + } + + /** + * Test validateForm() method. + */ + public function testValidateForm() { + $form = []; + $form_state = new FormState(); + + // Validate that when choosing to watermark, an image file is required. + $form_state->setValue('charts', 1); + $form_state->setValue('file', []); + $this->watermark_form->validateForm($form, $form_state); + $this->assertTrue( + $form_state->hasAnyErrors(), + 'If watermark charts was set to true, then the formValidate() method is expected to trigger an error if no watermark image was provided.' + ); + + $form_state->clearErrors(); + + // Validate that when choosing not to watermark, image file is not required. + $form_state->setValue('charts', 0); + $form_state->setValue('file', []); + $this->watermark_form->validateForm($form, $form_state); + $this->assertFalse( + $form_state->hasAnyErrors(), + 'If watermark charts was set to false, then the formValidate() method is expected to submit the form without a watermark image.' + ); + } + + /** + * Test submitForm() method. + */ + public function testSubmitForm() { + $phenotypes_settings = $this->config->getEditable('trpcultivate_phenotypes.settings'); + // The managed_file field is set to upload file into this directory. + $watermark_dir = $phenotypes_settings->get('trpcultivate.phenotypes.directory.watermark'); + + $form = []; + $form_state = new FormState(); + + // Create a test watermark image file. + $watermark_file = File::create([ + 'filename' => 'watermark.png', + 'uri' => $watermark_dir . 'watermark.png', + 'status' => 0, + ]); + + $watermark_file->save(); + + // Allow chart to be watermarked. + $allow_watermark = 1; + + $form_state->setValue('charts', $allow_watermark); + $form_state->setValue('file', [$watermark_file->id()]); + + $this->watermark_form->submitForm($form, $form_state); + + // Check the the watermart was set in the configuration for watermark. + $watermark_config = $phenotypes_settings->get('trpcultivate.phenotypes.watermark'); + + $this->assertEquals( + $watermark_config['charts'], + $allow_watermark, + 'The watermark configuration for option to watermark all charts must be set to value 1 (watermark all charts).' + ); + + // Reload the file object to pull the lastest update. + $watermark_file = File::load($watermark_file->id()); + + $this->assertEquals( + $watermark_config['image'], + $watermark_file->getFileUri(), + 'The watermark image file uri does not match the expected file uri.' + ); + } + +} diff --git a/trpcultivate_phenotypes/tests/src/Kernel/ServiceGenusOntologyTest.php b/trpcultivate_phenotypes/tests/src/Kernel/ServiceGenusOntologyTest.php index 4a7e7b4b..c135ebd0 100644 --- a/trpcultivate_phenotypes/tests/src/Kernel/ServiceGenusOntologyTest.php +++ b/trpcultivate_phenotypes/tests/src/Kernel/ServiceGenusOntologyTest.php @@ -1,9 +1,10 @@ set('is_a_test_environment', TRUE); + // Install module configuration. $this->installConfig(['trpcultivate_phenotypes']); + + // Fetch module settings. $this->config = \Drupal::configFactory()->getEditable('trpcultivate_phenotypes.settings'); - // Create a test chado instance and then set it in the container for use by our service. + // Create a test chado instance and then set it in the container for use by + // our service. $this->chado_connection = $this->createTestSchema(ChadoTestKernelBase::PREPARE_TEST_CHADO); - $this->container->set('tripal_chado.database', $this->chado_connection); - - // Create organism of type null (id: 1). - $test_insert_genus = $this->test_genus; - $ins_genus = " - INSERT INTO {1:organism} (genus, species, type_id) - VALUES - ('$test_insert_genus[0]', 'culinaris', 1), - ('$test_insert_genus[1]', 'arientinum', 1) - "; - $this->chado_connection->query($ins_genus); - - $this->service = \Drupal::service('trpcultivate_phenotypes.genus_ontology'); + // Genus Ontology Service. + $this->service_PhenoGenusOntology = \Drupal::service('trpcultivate_phenotypes.genus_ontology'); + $this->assertNotNull($this->service_PhenoGenusOntology, 'Failed to instantiate Genus Ontology Service.'); } - public function testGenusOntologyService() { - // Class created. - $this->assertNotNull($this->service, 'Genus ontology service not created.'); - - // TEST WHEN THERE IS A GENUS RECORD. - // Create genus records since a clean Tripal site has - // no organism/genus records and re-run routines carried out - // during install process. - - // Created genus of type null (id: 1). - $test_insert_genus = $this->test_genus; - - // #Test defineGenusOntology(). - $define_genusontology = $this->service->defineGenusOntology(); - $this->assertNotNull($define_genusontology, 'Failed to define genus ontology configuration.'); - // Is an array. - $is_array = (is_array($define_genusontology)) ? TRUE : FALSE; - $this->assertTrue($is_array, 'Define genus ontology returned an unexpected value.'); - - foreach($test_insert_genus as $g) { - $key = $this->service->formatGenus($g); - $this->assertNotNull($define_genusontology[ $key ], 'Failed to create genus ontology configuration with key: ' . $key); - } - - // #Test formatGenus(). - // Genus = formatting applied by formatGenus(). - $test_genus = [ - 'Lens' => 'lens', - 'Hello Genus' => 'hello_genus', - 'WOW GENUS' => 'wow_genus', - 'beautiful_genus' => 'beautiful_genus', - 'a genus ' => 'a_genus', - 'Y' => 'y', - ' Not cool genus ' => 'not_cool_genus', - ' ' => null + /** + * Data Provider: provides genus (organism) to test genus ontology service. + * + * @return array + * Each genus test scenario is an array with the following values: + * - A string, human-readable short description of the test scenario. + * - A string, the genus name. + * - A string, the species name. + * - An array of expected values, with the following keys: + * - 'config_key': A string, configuration key value used to identify a + * genus configuration. The key is the lower-cased of the genus and all + * spaces converted into underscore character. + * - 'config_array': An array of the configuration values keyed by the + * genus configuration key. + */ + public function provideGenusForGenusOntologyService() { + return [ + // #0: A one-word genus string value. + [ + 'one-word genus name', + 'Lens', + 'species-1', + [ + 'config_key' => 'lens', + 'config_array' => [ + 'lens' => [ + 'trait', + 'method', + 'unit', + 'database', + 'crop_ontology', + ], + ], + ], + ], + + // #1: A multi-word genus string value separated by spaces. + [ + 'multi-word genus name', + 'my favourite genus', + 'species-2', + [ + 'config_key' => 'my_favourite_genus', + 'config_array' => [ + 'my_favourite_genus' => [ + 'trait', + 'method', + 'unit', + 'database', + 'crop_ontology', + ], + ], + ], + ], + + // #2: A genus string in camel-case. + [ + 'a genus in camel case', + 'sooCool-Genus', + 'species-3', + [ + 'config_key' => 'soocool-genus', + 'config_array' => [ + 'soocool-genus' => [ + 'trait', + 'method', + 'unit', + 'database', + 'crop_ontology', + ], + ], + ], + ], ]; + } - foreach($test_genus as $base => $result) { - $format_genus = $this->service->formatGenus($base); - $this->assertEquals($format_genus, $result, 'Base genus key and formatted genus key do not match.'); - } - - // #Test loadGenusOntology(). - $is_saved = $this->service->loadGenusOntology(); - $this->assertTrue($is_saved, 'Failed to load genus ontology.'); - - // Compare what was registered in the config settings. - $config_genus_ontology = $this->config->get('trpcultivate.phenotypes.ontology.cvdbon'); - foreach($test_insert_genus as $genus) { - $g = $this->service->formatGenus($genus); - // Genus configuration found. - $this->assertNotNull($config_genus_ontology[ $g ], 'Failed to register a configuration with the key: ' . $g); - - // Genus configuration properties/variables are set to 0. - foreach($config_genus_ontology[ $g ] as $prop => $val) { - $is_config = (in_array($prop, ['trait', 'unit', 'method', 'database', 'crop_ontology'])) ? TRUE : FALSE; - $this->assertTrue($is_config, 'Genus ontology configuration has no property: ' . $g . ' - ' . $prop); - $this->assertEquals($val, 0, 'Genus ontology has unexpected default value (expecting 0): ' . $val); - } - } - - // #Test getGenusOntologyConfigValues(). - foreach($test_insert_genus as $genus) { - $genus_config = $this->service->getGenusOntologyConfigValues($genus); - $this->assertNotNull($genus_config, 'Failed to fetch value of a genus ontology configuration: ' . $genus); + /** + * Test genus ontology service. + * + * @param string $scenario + * Human-readable text description of the test scenario. + * @param string $genus + * A string, the genus name. + * @param string $species + * A string, the species name. + * @param array $expected + * An array of expected values, with the following keys: + * - 'config_key': A string, configuration key value used to identify a + * genus configuration. The key is the lower-cased of the genus and all + * spaces converted into underscore character. + * - 'config_array': An array of the configuration values keyed by the + * genus configuration key. + * + * @dataProvider provideGenusForGenusOntologyService + */ + public function testGenusOntologyService($scenario, $genus, $species, $expected) { + // Create an organism. + $organism_id = $this->chado_connection->insert('1:organism') + ->fields([ + 'genus' => $genus, + 'species' => $species, + ]) + ->execute(); + + $this->assertIsNumeric($organism_id, 'Unable to create organism in scenario ' . $scenario); + + // Test formatGenus(). + $genus_ontology_config_key = $this->service_PhenoGenusOntology->formatGenus($genus); + $this->assertEquals( + $expected['config_key'], + $genus_ontology_config_key, + 'Genus ontology configuration key does not match expected configuration key in scenario ' . $scenario + ); + + // Test defineGenusOntology(). + $genus_ontology_config_definition = $this->service_PhenoGenusOntology->defineGenusOntology(); + $this->assertNotNull( + $genus_ontology_config_definition, + 'Failed to define genus ontology configuration array in scenario ' . $scenario + ); + + $this->assertTrue( + is_array($genus_ontology_config_definition), + 'Genus ontology definition array returned an unexpected value type in scenario' . $scenario + ); + + $this->assertEquals( + $expected['config_array'], + $genus_ontology_config_definition, + 'Genus ontology definition does not match expected configuration array in sceneario ' . $scenario + ); + + $this->assertEquals( + $genus_ontology_config_key, + array_keys($genus_ontology_config_definition)[0], + 'The genus ontology configuration key does not match expected configuration key in scenario ' . $scenario + ); + + // Test loadGenusOntology(). + $is_created = $this->service_PhenoGenusOntology->loadGenusOntology(); + $this->assertTrue($is_created, 'Failed to load genus ontology in scenario ' . $scenario); + + // Compare the values registered in the config settings with the default + // load value. + $settings_genus_ontology_values = $this->config->get('trpcultivate.phenotypes.ontology.cvdbon'); + $default_load_value = 0; + + foreach ($settings_genus_ontology_values[$genus_ontology_config_key] as $config_var => $config_val) { + $this->assertTrue( + in_array($config_var, ['trait', 'unit', 'method', 'database', 'crop_ontology']), + 'Genus ontology configuration has no property: ' . $genus_ontology_config_key . ' - ' . $config_var . ' in scenario ' . $scenario + ); + + $this->assertEquals( + $config_val, + $default_load_value, + 'Genus ontology has unexpected default value (expecting ' . $default_load_value . '): ' . $config_var . ' - ' . $config_val . ' in scenario ' . $scenario + ); } - $not_valid_keys = [':p', -1, 0, 'abc', 999999, '', 'lorem_ipsum', '.', 'G', 'lenz', '@']; - foreach($not_valid_keys as $key) { - $not_found = $this->service->getGenusOntologyConfigValues($key); - $this->assertEquals($not_found, 0); + // Test getGenusOntologyConfigValues(). + // At this point, the genus configuration value still has the default + // load value of 0 set. + $default_config_values = $this->service_PhenoGenusOntology->getGenusOntologyConfigValues($genus); + $this->assertEquals( + $settings_genus_ontology_values[$genus_ontology_config_key], + $default_config_values, + 'Expected default config values do not match expected configuration values in scenario ' . $scenario + ); + + // Update the default load values of configuration to some values. + $this->setOntologyConfig($genus); + $set_config_values = $this->service_PhenoGenusOntology->getGenusOntologyConfigValues($genus); + + foreach ($set_config_values as $config_var => $config_val) { + $this->assertNotEquals( + $default_load_value, + $config_val, + 'The config ' . $config_var . ' must have a value greater than 0 (default value) in scenario ' . $scenario + ); } - // #Test saveGenusOntologyConfigValues(). - // loadGenusOntology() sets all configuration values for all genus to a default value - // 0. This test will set every configuration to null cv (id: 1) and null db (id: 1). - - // This would have came from a form submit method. + // Test saveGenusOntologyConfigValues(). $null_id = 1; - $genus_ontology_values = []; + $config_array = []; - foreach($define_genusontology as $genus_key => $config_values) { - foreach($config_values as $config_name) { - $genus_ontology_values[ $genus_key ][ $config_name ] = $null_id; + foreach ($genus_ontology_config_definition as $config_key => $config_vars) { + foreach ($config_vars as $config_var) { + // Set all configuration value to 1. + $config_array[$config_key][$config_var] = $null_id; } } - $is_saved = $this->service->saveGenusOntologyConfigValues($genus_ontology_values); - $this->assertTrue($is_saved, 'Failed to save genus ontology value.'); + $is_saved = $this->service_PhenoGenusOntology->saveGenusOntologyConfigValues($config_array); + $this->assertTrue($is_saved, 'Failed to save genus ontology value in scenario ' . $scenario); - // Test if all genus ontology config got nulled. - foreach($test_insert_genus as $genus) { - $genus_config = $this->service->getGenusOntologyConfigValues($genus); - foreach($genus_config as $config_name => $config_value) { - $this->assertEquals($config_value, $null_id, 'Genus ontology configuration has unexpected value (expecting 1): ' . $config_value); - } + // See if all configuration terms got the null id value of 1. + $nulled_config_values = $this->service_PhenoGenusOntology->getGenusOntologyConfigValues($genus); + foreach ($nulled_config_values as $null_value) { + $this->assertEquals( + $null_value, + $null_id, + 'Genus ontology configuration has unexpected value (expecting ' . $null_id . '): ' . $null_value . ' in scenario ' . $scenario); } - // Active Genus list. - $active_genus = $this->service->getConfiguredGenusList(); - $extra_item = array_diff($active_genus, $this->test_genus); - - // Assert no extra item thus both arrays are the same. - $this->assertEmpty($extra_item, 'Active genus arrays do not match.'); + // Test getConfiguredGenusList(). + $active_genus = $this->service_PhenoGenusOntology->getConfiguredGenusList(); + $this->assertTrue( + in_array($genus, $active_genus), + 'The configured genus could not be found in the list of active genus in scenario ' . $scenario + ); } + } diff --git a/trpcultivate_phenotypes/tests/src/Kernel/ServiceGenusProjectTest.php b/trpcultivate_phenotypes/tests/src/Kernel/ServiceGenusProjectTest.php index ab360bb6..3618e231 100644 --- a/trpcultivate_phenotypes/tests/src/Kernel/ServiceGenusProjectTest.php +++ b/trpcultivate_phenotypes/tests/src/Kernel/ServiceGenusProjectTest.php @@ -1,11 +1,10 @@ 0, - 'genus' => 0, - 'genus_id' => 0, - 'projectprop_id' => 0, - 'second_genus' => 0, - 'second_genus_id' => 0 - ]; - - /** - * Project that is set with a genus. + * @var string */ - private $project; + private $alt_genus = 'AlternativeGenus'; /** * {@inheritdoc} @@ -73,150 +65,136 @@ protected function setUp(): void { // Install module configuration. $this->installConfig(['trpcultivate_phenotypes']); - $this->config = \Drupal::configFactory()->getEditable('trpcultivate_phenotypes.settings'); - // Set ontology.term: genus to null (id: 1). - $this->config->set('trpcultivate.phenotypes.ontology.terms.genus', 1); + // Fetch module settings. + $this->config = \Drupal::configFactory()->getEditable('trpcultivate_phenotypes.settings'); - // Test Chado database. - // Create a test chado instance and then set it in the container for use by our service. + // Create a test chado instance and then set it in the container for use by + // our service. $this->chado_connection = $this->createTestSchema(ChadoTestKernelBase::PREPARE_TEST_CHADO); - $this->container->set('tripal_chado.database', $this->chado_connection); - // Prepare by adding test records to genus, project and projectproperty - // to relate a genus to a project. - $project = 'Project - ' . uniqid(); - $this->project = $project; - $project_id = $this->chado_connection->insert('1:project') + // Set terms used to create relations. + $this->setTermConfig(); + + // Create and configure a genus to be used to switch a project genus to + // using this genus. + $organism_id = $this->chado_connection->insert('1:organism') ->fields([ - 'name' => $project, - 'description' => $project . ' : Description' + 'genus' => $this->alt_genus, + 'species' => 'some species', ]) ->execute(); - $this->ins['project_id'] = $project_id; + $this->assertIsNumeric($organism_id, 'Unable to create alternative genus'); - $genus = 'Wild Genus ' . uniqid(); - $genus_id = $this->chado_connection->insert('1:organism') - ->fields([ - 'genus' => $genus, - 'species' => 'Wild Species', - 'type_id' => 1 - ]) - ->execute(); + // Configure the genus. + $this->setOntologyConfig($this->alt_genus); + } - $this->ins['genus_id'] = $genus_id; - $this->ins['genus'] = $genus; + /** + * Data Provider: provides genus and project to test genus project service. + * + * @return array + * Each genus-project test scenario is an array witht the following values: + * - A string, human-readable short description of the test scenario. + * - A string, the name or title of a project. + * - An array, the genus and species of the organism that will be + * paired with the project. Keyed by 'genus' and 'species'. + * - An array of expected values, with the following keys: + * - 'project_genus': the expected genus returned by the method + * getGenusOfProject(). + * - 'alternative_genus': a genus returned after setting a genus. + */ + public function provideGenusProjectForGenusProjectService() { + return [ + // #0: A project with configured genus. + [ + 'A project with configured genus', + 'Project - Plant Breeding', + [ + 'genus' => 'a genus', + 'species' => 'a species', + ], + [ + 'project_genus' => 'a genus', + 'alternative_genus' => 'AlternativeGenus', + ], + ], + ]; + } - $prop_id = $this->chado_connection->insert('1:projectprop') + /** + * Test genus project service. + * + * @param string $scenario + * Human-readable text description of the test scenario. + * @param string $project_name + * A string, the name or title of a project. + * @param array $project_genus + * An array, the genus and species of the organism that will be + * paired with the project. Keyed by 'genus' and 'species'. + * @param array $expected + * An array of expected values, with the following keys: + * - 'project_genus': the expected genus returned by the method + * getGenusOfProject(). + * - 'alternative_genus': a genus returned after setting a genus. + * + * @dataProvider provideGenusProjectForGenusProjectService + */ + public function testGenusProjectService($scenario, $project_name, $project_genus, $expected) { + // Create the project record. + $project_id = $this->chado_connection->insert('1:project') ->fields([ - 'project_id' => $project_id, - 'type_id' => 1, - 'value' => $genus + 'name' => $project_name, + 'description' => 'A project description', ]) ->execute(); - $this->ins['projectprop_id'] = $prop_id; - - // Create Genus Ontology configuration. - // All configuration and database value to null (id: 1). - $config_name = str_replace(' ', '_', strtolower($genus)); - $genus_ontology_config = [ - 'trait' => 1, - 'unit' => 1, - 'method' => 1, - 'database' => 1, - 'crop_ontology' => 1 - ]; + $this->assertIsNumeric($project_id, 'Unable to create project in scenario ' . $scenario); - $this->config->set('trpcultivate.phenotypes.ontology.cvdbon.' . $config_name, $genus_ontology_config); - - // Insert a secondary genus to be used to test when setting up a genus - // where replace existing genus is enabled. - $genus = 'Cultivated Genus ' . uniqid(); - $genus_id = $this->chado_connection->insert('1:organism') + // Create the genus record. + $organism_id = $this->chado_connection->insert('1:organism') ->fields([ - 'genus' => $genus, - 'species' => 'Cultivated Species', - 'type_id' => 1 + 'genus' => $project_genus['genus'], + 'species' => $project_genus['species'], ]) ->execute(); - // Configure this other genus. - // All configuration and database value to null (id: 1). - $config_name = str_replace(' ', '_', strtolower($genus)); - $genus_ontology_config = [ - 'trait' => 1, - 'unit' => 1, - 'method' => 1, - 'database' => 1, - 'crop_ontology' => 1 - ]; + $this->assertIsNumeric($organism_id, 'Unable to create project genus in scenario ' . $scenario); - $this->config->set('trpcultivate.phenotypes.ontology.cvdbon.' . $config_name, $genus_ontology_config); + // Configure the genus. + $this->setOntologyConfig($project_genus['genus']); - $this->ins['second_genus_id'] = $genus_id; - $this->ins['second_genus'] = $genus; + // Genus Project Service. + $this->service_PhenoGenusProject = \Drupal::service('trpcultivate_phenotypes.genus_project'); + $this->assertNotNull($this->service_PhenoGenusProject, 'Failed to instantiate Genus Project Service in scenario ' . $scenario); - // Save all genus ontology config. - $this->config->save(); - - // Term service. - $this->service = \Drupal::service('trpcultivate_phenotypes.genus_project'); - } - - public function testGenusProjectService() { - // Class created. - $this->assertNotNull($this->service, 'Term service not created.'); + // Test setGenusToProject(). + $is_set = $this->service_PhenoGenusProject->setGenusToProject($project_id, $project_genus['genus'], TRUE); + $this->assertTrue($is_set, 'Project Genus Service failed to set a genus to project in scenario ' . $scenario); - // Assert all relevant records were created in setup. - foreach($this->ins as $key => $value) { - $this->assertNotNull($value, $key . ' Test record not created.'); - } + // Keep the same project genus by setting the replace flag to FALSE. + $is_set = $this->service_PhenoGenusProject->setGenusToProject($project_id, $project_genus['genus'], FALSE); + $this->assertTrue($is_set, 'Project Genus Service failed to set a genus to project in scenario ' . $scenario); // Test getGenusOfProject(). - $genus_project = $this->service->getGenusOfProject($this->ins['project_id']); - - $this->assertNotNull($genus_project, 'Genus of a project returned null: project_id - ' . $this->ins['project_id']); - $this->assertEquals($genus_project['genus'], $this->ins['genus'], 'Genus does not match expected genus: ' . $genus_project['genus']); - - // Test setGenusToProject(). - // From Wild genus to cultivated genus. Replace genus flag enabled. - $set = $this->service->setGenusToProject($this->ins['project_id'], $this->ins['second_genus'], TRUE); - $this->assertTrue($set, 'Change of genus failed: project_id - ' . $this->ins['project_id'] . ' to ' . $this->ins['second_genus']); - $new_genus = $this->service->getGenusOfProject($this->ins['project_id']); - $this->assertEquals($new_genus['genus'], $this->ins['second_genus'], 'Genus does not match expected genus: ' . $this->ins['second_genus']); - - // Does nothing. replace option is default to false. - // This will throw an error since target genus is not configured. - // $set = $this->service->setGenusToProject($this->ins['project_id'], 'REPLACEMENT GENUS'); - // $this->assertTrue($set, 'Change of genus failed: project_id - ' . $this->ins['project_id'] . ' to ' . $genus); - - // No relationship yet. Create a relationship in projectprop table. - // Create a new project. - $project = 'New Project - ' . uniqid(); - $project_id = $this->chado_connection->insert('1:project') - ->fields([ - 'name' => $project, - 'description' => $project . ' : Description' - ]) - ->execute(); - - $set = $this->service->setGenusToProject($project_id, $this->ins['second_genus']); - $this->assertTrue($set, 'Change of genus failed: project_id - ' . $project_id . ' to ' . $this->ins['second_genus']); - - $new_project_genus = $this->service->getGenusOfProject($project_id); - $this->assertEquals($new_project_genus['genus'], $this->ins['second_genus'], 'Genus does not match expected genus: ' . $this->ins['second_genus']); - - // Test method inserted correct record into projectprop table. - $projectprop = $this->chado_connection->query(" - SELECT * FROM {1:projectprop} - WHERE project_id = :project_id AND type_id = :term_genus AND value = :value_genus LIMIT 1 - ", [':project_id' => $project_id, ':term_genus' => 1, ':value_genus' => $new_project_genus['genus']]) - ->fetchObject(); - - $this->assertNotNull($projectprop->projectprop_id, 'Method setGenusToProject failed to create a record in projectprop table.'); - $this->assertEquals($new_project_genus['genus'], $projectprop->value, 'Genus set value in projectprop does not match expected genus.'); - $this->assertEquals($project_id, $projectprop->project_id, 'Project id set value in projectprop does not match expected project id.'); + $genus_of_project = $this->service_PhenoGenusProject->getGenusOfProject($project_id); + $this->assertEquals( + $expected['project_genus'], + $genus_of_project['genus'], + 'The genus of project does not match expected genus in scenario ' . $scenario + ); + + // Replace the genus with the alternative genus. + $is_alt_genus_set = $this->service_PhenoGenusProject->setGenusToProject($project_id, $this->alt_genus, TRUE); + $this->assertTrue($is_alt_genus_set, 'Project Genus Service failed to set alternate genus to project in scenario ' . $scenario); + + $new_genus_of_project = $this->service_PhenoGenusProject->getGenusOfProject($project_id); + $this->assertEquals( + $expected['alternative_genus'], + $new_genus_of_project['genus'], + 'The genus of project does not match expected alternative genus in scenario ' . $scenario + ); } + } diff --git a/trpcultivate_phenotypes/tests/src/Kernel/ServiceTermTest.php b/trpcultivate_phenotypes/tests/src/Kernel/ServiceTermTest.php index 69c0f02b..340602e1 100644 --- a/trpcultivate_phenotypes/tests/src/Kernel/ServiceTermTest.php +++ b/trpcultivate_phenotypes/tests/src/Kernel/ServiceTermTest.php @@ -1,44 +1,49 @@ 2 && in_array($file, $tripal_chado_api)) { - include_once($tripal_chado_path . $file); + include_once $tripal_chado_path . $file; } } closedir($handle); } - // Create a test chado instance and then set it in the container for use by our service. + // Create a test chado instance and then set it in the container for use by + // our service. $this->chado_connection = $this->createTestSchema(ChadoTestKernelBase::PREPARE_TEST_CHADO); $this->container->set('tripal_chado.database', $this->chado_connection); - // Term service. - $this->service = \Drupal::service('trpcultivate_phenotypes.terms'); + // Term Service. + $this->service_PhenoTerms = \Drupal::service('trpcultivate_phenotypes.terms'); + $this->assertNotNull($this->service_PhenoTerms, 'Failed to instantiate Terms Service.'); + + // Set terms used to create relations. + $this->setTermConfig(); } - public function testTermService() { - // Class was created. - $this->assertNotNull($this->service); + /** + * Data Provider: provides term identifier to test Term Service getTermId(). + * + * @return array + * Each term identifier test scenario is an array with the following values: + * - A string, human-readable short descriptionn of the test scenario. + * - A string, term identifier input. + * - An array of expected values, with the following keys. + * - 'term_exists': boolean value to idicate if a term identifier exits + * of if it is a non-existent identifier. + */ + public function provideTermIdentifierForGetTermIdMethod() { + return [ + // #0: An integer term identifier. + [ + 'integer term identifier', + 99999, + [ + 'term_exists' => FALSE, + ], + ], + + // #1: An empty string value. + [ + 'empty string value', + '', + [ + 'term_exists' => FALSE, + ], + ], + + // #2: A non-existent term indentifier. + [ + 'non-existent term identifier', + 'not a term identifier', + [ + 'term_exists' => FALSE, + ], + ], + + // #3: A valid term unique identifier. + [ + 'valid identifier', + 'method_to_trait_relationship_type', + [ + 'term_exists' => TRUE, + ], + ], + + ]; + } + + /** + * Data Provider: provides terms to test Term Service saveTermConfigValues(). + * + * @return array + * Each term test scenario is an array with the following values: + * - A string, human-readable short descriptionn of the test scenario. + * - An array, term input with the following keys: + * - 'name': the name of the term. + * - 'cv': the cv vocabulary the term will be associated. + * - A string, the term identifier of the module the term array will + * be saved and mapped to. + * - An array of expected values, with the following keys. + * - 'is_saved': the expected return value of the method. + */ + public function provideTermsForSaveTermConfigValuesMethod() { + return [ + // #0: New term. + [ + 'new term', + [ + 'name' => 'New Term', + 'cv' => 'local', + ], + 'genus', + [ + 'is_saved' => TRUE, + ], + ], + + // #1: Existing term. + [ + 'existing term', + [ + 'name' => 'null', + 'cv' => 'null', + ], + 'location', + [ + 'is_saved' => TRUE, + ], + ], + ]; + } + + /** + * Test Term Service getTermId() method. + * + * @param string $scenario + * A string, human-readable short descriptionn of the test scenario. + * @param string $input_term_identifier + * A string, term identifier input. + * @param array $expected + * An array of expected values, with the following keys. + * - 'term_exists': boolean value to idicate if a term identifier exits + * (TRUE) or of if it is a non-existent identifier (FALSE). + * + * @dataProvider provideTermIdentifierForGetTermIdMethod + */ + public function testGetTermId($scenario, $input_term_identifier, $expected) { + $term_id = $this->service_PhenoTerms->getTermId($input_term_identifier); + $term_exists = ($term_id > 0) ? TRUE : FALSE; + + $this->assertEquals( + $expected['term_exists'], + $term_exists, + 'getTermId() should return ' . $expected['term_exists'] . ' for the input indentifier in scenario ' . $scenario + ); + } + /** + * Test Term Service saveTermConfigValues() method. + * + * @param string $scenario + * A string, human-readable short descriptionn of the test scenario. + * @param array $input_term + * An array, term input with the following keys: + * - 'name': the name of the term. + * - 'cv': the cv vocabulary the term will be associated. + * @param string $term_identifier + * A string, the term identifier of the module the term array will + * be saved and mapped to. + * @param array $expected + * An array of expected values, with the following keys. + * - 'is_saved': the expected return value of the method. + * + * @dataProvider provideTermsForSaveTermConfigValuesMethod + */ + public function testSaveTermConfigValuesMethod($scenario, $input_term, $term_identifier, $expected) { + // Create or fectch input term. + $term_exists = $this->chado_connection->select('1:cvterm', 'cvt') + ->fields('cvt', ['cvterm_id']) + ->condition('cvt.name', $input_term['name']) + ->execute() + ->fetchField(); + + if ($term_exists) { + $cvterm_id = $term_exists; + } + else { + $cvterm = chado_insert_cvterm($input_term, [], $schema = NULL); + $cvterm_id = $cvterm->cvterm_id; + } + + $is_saved = $this->service_PhenoTerms->saveTermConfigValues([$term_identifier => $cvterm_id]); + $this->assertEquals( + $expected['is_saved'], + $is_saved, + 'saveTermConfigValues() should return ' . $expected['is_saved'] . ' in scenario ' . $scenario + ); + + // Test to see if the configuration value is the input term saved. + $this->assertEquals( + $this->service_PhenoTerms->getTermId($term_identifier), + $cvterm_id, + 'saveTermConfigValues() failed to save term in the expected term identifier in scenario ' . $scenario + ); + } + + /** + * Test Term Service. + */ + public function testTermService() { // Test defineTerms(). - $define_terms = $this->service->defineTerms(); + $define_terms = $this->service_PhenoTerms->defineTerms(); $keys = array_keys($define_terms); $this->assertNotNull($define_terms); @@ -96,8 +276,8 @@ public function testTermService() { // Compare what was defined and the pre-defined terms in the // config settings file. $term_set = $this->config->get('trpcultivate.default_terms.term_set'); - foreach($term_set as $id => $terms) { - foreach($terms['terms'] as $term) { + foreach ($term_set as $id => $terms) { + foreach ($terms['terms'] as $term) { $this->assertNotNull($term['config_map']); $this->assertArrayHasKey($term['config_map'], $define_terms, "The config_map retrieved from config should match one of the keys from defineTerms()."); @@ -105,14 +285,13 @@ public function testTermService() { } // Test loadTerms(). - $is_loaded = $this->service->loadTerms(); + $is_loaded = $this->service_PhenoTerms->loadTerms(); $this->assertTrue($is_loaded, "We expect loadTerms() to return TRUE to indicate it successfully loaded the terms."); - // Test getTermId(). - $expected = []; - foreach($keys as $key) { - $id = $this->service->getTermId($key); + // Test values matched to what was loaded into the table. + foreach ($keys as $term_identifier) { + $id = $this->service_PhenoTerms->getTermId($term_identifier); $this->assertNotNull($id, "We should have been able to retrieve the term based on the config_map value but we were not."); $this->assertGreaterThan(0, $id, @@ -120,59 +299,22 @@ public function testTermService() { // Keep track of our expectations. // mapping of config key => [cvterm_id, expected cvterm name]. - $expected[ $key ] = [ - 'cvterm_id' => $id, - 'name' => $define_terms[ $key ]['name'] - ]; - } - - $not_valid_keys = [':p', -1, 0, 'abc', 999999, '', 'lorem_ipsum', '.']; - foreach($not_valid_keys as $n) { - // Invalid config name key, will return 0 value. - $v = $this->service->getTermId($n); - $this->assertEquals($v, 0); - } + $cvterm_id = $id; + $expected_cvterm_name = $define_terms[$term_identifier]['name']; - // Test values matched to what was loaded into the table. - $chado = $this->chado_connection; - foreach ($expected as $config_key => $expected_deets) { - $expected_cvterm_name = $expected_deets['name']; - $cvterm_id = $expected_deets['cvterm_id']; - $query = $chado->select('1:cvterm', 'cvt') + $saved_cvterm_name = $this->chado_connection->select('1:cvterm', 'cvt') ->fields('cvt', ['name']) - ->condition('cvt.cvterm_id', $cvterm_id); - $cvterm_name = $query->execute()->fetchField(); - $this->assertNotNull($cvterm_name, - "We should have been able to retrieve the term $expected_cvterm_name using the id $cvterm_id but could not."); - $this->assertEquals($expected_cvterm_name, $cvterm_name, - "The name of the cvterm with the id $cvterm_id did not match the one we expected based on the config key $config_key."); - } + ->condition('cvt.cvterm_id', $cvterm_id) + ->execute() + ->fetchField(); - // #Test saveTermConfigValues(). - // With the loadTerms above, each term configuration was set with - // a term id number that matches a term in chado.cvterm. This test - // will set all terms configuration to null (id: 1). - - // This would have came from form submit method. - $config_values = []; - foreach (array_keys($define_terms) as $key) { - $config_values[ $key ] = 1; - } - - $is_saved = $this->service->saveTermConfigValues($config_values); - $this->assertTrue($is_saved, - "We expected the saveTermConfigValues() method to return TRUE."); - - foreach($config_values as $key => $set_id) { - // Test if all config got nulled. - $retrieved_id = $this->service->getTermId($key); - $this->assertEquals($set_id, $retrieved_id, - "We expected the retrieved id to match the one we set it to but it did not."); + $this->assertNotNull($saved_cvterm_name, + "We should have been able to retrieve the term $expected_cvterm_name using the id $cvterm_id but could not."); + $this->assertEquals( + $expected_cvterm_name, + $saved_cvterm_name, + "The name of the cvterm with the id $cvterm_id did not match the one we expected based on the config key $term_identifier."); } - - // Nothing to save. - $not_saved = $this->service->saveTermConfigValues([]); - $this->assertFalse($not_saved, - "We should not be able to call saveTermConfigValues() with an empty array."); } + } diff --git a/trpcultivate_phenotypes/tests/src/Traits/PhenotypeImporterTestTrait.php b/trpcultivate_phenotypes/tests/src/Traits/PhenotypeImporterTestTrait.php index 7c8c2000..79b04c4b 100644 --- a/trpcultivate_phenotypes/tests/src/Traits/PhenotypeImporterTestTrait.php +++ b/trpcultivate_phenotypes/tests/src/Traits/PhenotypeImporterTestTrait.php @@ -1,15 +1,19 @@ 'cv_id', 'method' => 'cv_id', 'crop_ontology' => 'cv_id', - 'database' => 'db_id' + 'database' => 'db_id', ]; foreach ($reference as $key => $id_column) { $table = ($id_column == 'cv_id') ? 'cv' : 'db'; @@ -67,7 +72,7 @@ public function setOntologyConfig(string $genus, array $details = []) { // Now we will want to set the name. // -- no name but we have the id. - if (empty($details[$key]['name']) AND !empty($details[$key][$id_column])) { + if (empty($details[$key]['name']) and !empty($details[$key][$id_column])) { $table = ($id_column == 'cv_id') ? 'cv' : 'db'; $id = $details[$key][$id_column]; $name = $this->chado_connection->select("1:$table", 'tbl') @@ -80,7 +85,7 @@ public function setOntologyConfig(string $genus, array $details = []) { $details[$key]['name'] = $name; } // -- no id but we have the name. - elseif (!empty($details[$key]['name']) AND empty($details[$key][$id_column])) { + elseif (!empty($details[$key]['name']) and empty($details[$key][$id_column])) { $name = $details[$key]['name']; $id = $this->chado_connection->select("1:$table", 'tbl') ->fields('tbl', [$id_column]) @@ -94,7 +99,7 @@ public function setOntologyConfig(string $genus, array $details = []) { // -- we still don't have the id so create one. if (empty($details[$key][$id_column])) { - // set the name if it's not already. + // Set the name if it's not already. $details[$key]['name'] = $details[$key]['name'] ?: $genus . ' ' . $key . uniqid(); $name = $details[$key]['name']; $id = $this->chado_connection->insert("1:$table") @@ -142,13 +147,14 @@ public function setTermConfig(array $terms = []) { if (!array_key_exists($key, $terms)) { $terms[$key] = 0; } - // If the term value is not set, then choose a random integer between 10 - 300. - // We know there are at least 300 terms in the cvterm table so this is pretty safe. - if(empty($terms[$key])) { - $terms[$key] = random_int(10,300); + // If the term value is not set, then choose a random integer + // between 10 - 300. We know there are at least 300 terms in + // the cvterm table so this is pretty safe. + if (empty($terms[$key])) { + $terms[$key] = random_int(10, 300); } - // Now set the configuration + // Now set the configuration. $config->set("trpcultivate.phenotypes.ontology.terms.$key", $terms[$key]); } @@ -175,8 +181,9 @@ public function setTermConfig(array $terms = []) { * Either 'none' for unreadable or the octet (see chmod) * 0600: read + write for owner, nothing for everyone else * 0644: read + write for owner, read only for everyone else - * 0777: read + write + execute for everyone - * @return File + * 0777: read + write + execute for everyone. + * + * @return \Drupal\file\Entity\File * The Drupal managed file object created. */ protected function createTestFile($details) { @@ -204,14 +211,14 @@ protected function createTestFile($details) { $file_id = $file->id(); $file_uri = $file->getFileUri(); - // If a test file fixture was provided, create a copy and set this file copy as - // the file uri value in the file object for this test file. + // If a test file fixture was provided, create a copy and set this file copy + // as the file uri value in the file object for this test file. if (array_key_exists('file', $details['content']) && !empty($details['content']['file'])) { $path_to_file_fixture = __DIR__ . '/../Fixtures/' . $details['content']['file']; $this->assertFileIsReadable( $path_to_file_fixture, - 'Unable to setup FILE ' . $file_id . ' because cannot access Fixture file at ' . $path_to_file_fixture + 'Unable to setup FILE ' . $file_id . ' because cannot access Fixture file at ' . $path_to_file_fixture ); copy($path_to_file_fixture, $file_uri); @@ -223,7 +230,6 @@ protected function createTestFile($details) { } // Set other file attributes: - // Set the size of the file. // This is usually used if the file is empty in which case this is 0. if (isset($details['filesize'])) { @@ -260,4 +266,5 @@ protected function createTestFile($details) { return $file; } + } diff --git a/trpcultivate_phenotypes/tests/src/Unit/ConfigRRulesFormTest.php b/trpcultivate_phenotypes/tests/src/Unit/ConfigRRulesFormTest.php index 46f586aa..c120ec99 100644 --- a/trpcultivate_phenotypes/tests/src/Unit/ConfigRRulesFormTest.php +++ b/trpcultivate_phenotypes/tests/src/Unit/ConfigRRulesFormTest.php @@ -18,8 +18,12 @@ * @group trpcultivate_phenotypes */ class ConfigRRulesFormTest extends UnitTestCase { - - private $rrulesform; + /** + * An instance of the R rules configuration form. + * + * @var \Drupal\trpcultivate_phenotypes\Form\TripalCultivatePhenotypesRSettingsForm + */ + protected $rrulesform; /** * {@inheritdoc} diff --git a/trpcultivate_phenotypes/tests/src/Unit/ConfigWatermarkFormTest.php b/trpcultivate_phenotypes/tests/src/Unit/ConfigWatermarkFormTest.php index b283ee60..a17d47cb 100644 --- a/trpcultivate_phenotypes/tests/src/Unit/ConfigWatermarkFormTest.php +++ b/trpcultivate_phenotypes/tests/src/Unit/ConfigWatermarkFormTest.php @@ -2,11 +2,11 @@ namespace Drupal\Tests\trpcultivate_phenotypes\Unit; +use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\Config\Config; use Drupal\Core\Config\ConfigFactoryInterface; -use Drupal\Core\Config\TypedConfigManagerInterface; -use Drupal\Core\DependencyInjection\ContainerBuilder; -use Drupal\Core\File\FileUrlGeneratorInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\File\FileUrlGenerator; use Drupal\Core\Form\FormState; use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\StringTranslation\TranslationInterface; @@ -21,29 +21,34 @@ */ class ConfigWatermarkFormTest extends UnitTestCase { + /** + * Class instance of watermark controller settings form. + * + * @var \Drupal\trpcultivate_phenotypes\Form\TripalCultivatePhenotypesWatermarkSettingsForm + */ + protected $watermark_form; + /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); - // Create container. - $container = new ContainerBuilder(); - \Drupal::setContainer($container); - - // Mock config since the Watermark form extends configFormBase and expects - // a configuration settings. Called in validateForm(). + // Mock file url generator. + $mock_file_url_generator = $this->createMock(FileUrlGenerator::class); + // Mock file entity manager. + $mock_file_entity_manager = $this->createMock(EntityTypeManagerInterface::class); + // Mock configuration. $watermark_config_mock = $this->prophesize(Config::class); - $watermark_config_mock->get('trpcultivate.phenotypes.watermark')->willReturn([ - 'charts' => FALSE, - 'image' => NULL, - 'file_ext' => ['png', 'gif'], - ]); + $watermark_config_mock->get('trpcultivate.phenotypes.watermark') + ->willReturn([ + 'charts' => FALSE, + 'image' => NULL, + 'file_ext' => ['png', 'gif'], + ]); $watermark_config_mock->get('trpcultivate.phenotypes.directory.watermark') ->willReturn('public://TripalCultivatePhenotypes/watermark/'); - // When watermark form rebuilds calling the module settings, return - // only the watertmark configuration settings above exclude other config. $all_config_mock = $this->prophesize(ConfigFactoryInterface::class); $all_config_mock->getEditable('trpcultivate_phenotypes.settings') ->willReturn($watermark_config_mock); @@ -51,73 +56,85 @@ protected function setUp(): void { // Isolated configuration for watermark configuration. $watermark_config = $all_config_mock->reveal(); - // Typed Config Manager requirement for ConfigForm dependancy injection. - $typed_config_mock = $this->prophesize(TypedConfigManagerInterface::class); - $typed_config = $typed_config_mock->reveal(); - - // Class WatermarkForm class instance. - $watermark_form = new TripalCultivatePhenotypesWatermarkSettingsForm($watermark_config, $typed_config); + $this->watermark_form = new TripalCultivatePhenotypesWatermarkSettingsForm($mock_file_url_generator, $mock_file_entity_manager, $watermark_config); - // Requirement of the container. - // -- Translation. + // Mock translation interface. $mock = $this->prophesize(TranslationInterface::class); $translation = $mock->reveal(); - $watermark_form->setStringTranslation($translation); - // -- Messenger. + $this->watermark_form->setStringTranslation($translation); + // Mock messenger interface. $mock = $this->prophesize(MessengerInterface::class); $messenger = $mock->reveal(); - $watermark_form->setMessenger($messenger); - // -- File URL Generator. - $mock = $this->prophesize(FileUrlGeneratorInterface::class); - $fileGenerator = $mock->reveal(); - $container->set('file_url_generator', $fileGenerator); + $this->watermark_form->setMessenger($messenger); + + $container = new ContainerBuilder(); + $container->set('config.factory', $watermark_config); + \Drupal::setContainer($container); + } - $container->set('watermark.config', $watermark_form); + /** + * Test watermark form id matches expected value. + */ + public function testFormId() { + $form_id = $this->watermark_form->getFormId(); + + // Form id set matches. + $this->assertEquals( + 'trpcultivate_phenotypes_watermark_settings_form', + $form_id, + 'The form id returned by getFormId() does not match expected form id value.' + ); } /** - * Test build form functionality of RRulesForm class. + * Test buildForm() method. */ public function testBuildForm() { - $watermark = \Drupal::service('watermark.config'); - $form = []; $form_state = new FormState(); - $config_form = $watermark->buildForm($form, $form_state); + + $config_form = $this->watermark_form->buildForm($form, $form_state); // Form theme is system configuration type. - $this->assertEquals('system_config_form', $config_form['#theme']); - // Field types. - $this->assertEquals('radios', $config_form['charts']['#type']); + $this->assertEquals( + 'system_config_form', + $config_form['#theme'], + 'The theme of the form generated by buildForm() method does not match expected theme.' + ); + + // Form has radio button field. + $this->assertEquals( + 'radios', + $config_form['charts']['#type'], + 'The form generated by buildForm() method is missing a form field of type radio button.', + ); } /** - * Test validate functionality of WatermarkForm class. + * Test validateForm() method. */ public function testValidateForm() { - $watermark = \Drupal::service('watermark.config'); - - // Test if it is the watermark config form using the form id. - $this->assertEquals('trpcultivate_phenotypes_watermark_settings_form', $watermark->getFormId()); - - // Method formValidate requires 2 parameters $form and $form_state. - $form_state = new FormState(); $form = []; + $form_state = new FormState(); // Validate that when choosing to watermark, an image file is required. $form_state->setValue('charts', 1); $form_state->setValue('file', []); - $watermark->validateForm($form, $form_state); - $this->assertTrue($form_state->hasAnyErrors()); + $this->watermark_form->validateForm($form, $form_state); + $this->assertTrue( + $form_state->hasAnyErrors(), + 'If watermark charts was set to true, then the formValidate() method is expected to trigger an error if no watermark image was provided.' + ); $form_state->clearErrors(); - // Validate that when choosing not to watermark, - // an image file is not required. + // Validate that when choosing not to watermark, image file is not required. $form_state->setValue('charts', 0); $form_state->setValue('file', []); - $watermark->validateForm($form, $form_state); - $this->assertFalse($form_state->hasAnyErrors()); + $this->watermark_form->validateForm($form, $form_state); + $this->assertFalse( + $form_state->hasAnyErrors(), + 'If watermark charts was set to false, then the formValidate() method is expected to submit the form without a watermark image.' + ); } - } diff --git a/trpcultivate_phenotypes/trpcultivate_phenotypes.install b/trpcultivate_phenotypes/trpcultivate_phenotypes.install index 570ece3f..3de18612 100644 --- a/trpcultivate_phenotypes/trpcultivate_phenotypes.install +++ b/trpcultivate_phenotypes/trpcultivate_phenotypes.install @@ -5,21 +5,30 @@ * Defines hooks required during install of Tripal Cultivate Phenotypes. */ -use \Drupal\Core\File\FileSystemInterface; +use Drupal\Core\File\FileSystemInterface; - /** - * Implements hook_install(). - */ +/** + * Implements hook_install(). + * + * When the module is installed, we use the configuration values to setup + * the site for this module. Specifically, + * - create file directories. + * - register tripaljobs to insert the cvterms we use as defaults for + * our term configuration. The callback for this job is in the .module file. + * + * @see config/install + * @see config/schema + * @see trpcultivate_phenotypes.module + */ function trpcultivate_phenotypes_install() { // Setup file system/directories used to store files generated by and file // submitted to Tripal Cultivate Phenotyopes modules suite. $file_system = \Drupal::service('file_system'); - - // @see config install and schema. + $dirs = \Drupal::config('trpcultivate_phenotypes.settings') ->get('trpcultivate.phenotypes.directory'); - foreach($dirs as $i => $dir) { + foreach ($dirs as $dir) { if (!empty($dir)) { // Setup directory when configuration entry is set to // a directory, skip the blank/empty values. @@ -27,16 +36,22 @@ function trpcultivate_phenotypes_install() { } } - // Register a Tripal Job instance to install default terms and + // Register a Tripal Job instance to install default terms and // set term configuration variable. - // @see module file for the callback function. $user = \Drupal::currentUser(); - $uid = $user->id(); - + try { - tripal_add_job('Tripal Cultivate Phenotypes: Install Ontology and Terms', 'tripal', 'trpcultivate_phenotypes_install_ontologyterms', [], $uid, 10, []); + tripal_add_job( + 'Tripal Cultivate Phenotypes: Install Ontology and Terms', + 'tripal', + 'trpcultivate_phenotypes_install_ontologyterms', + [], + $user->id(), + 10, + [] + ); } catch (\Exception $e) { throw new \Exception('Cannot create a job to install terms:' . $e->getMessage); } -} \ No newline at end of file +} diff --git a/trpcultivate_phenotypes/trpcultivate_phenotypes.module b/trpcultivate_phenotypes/trpcultivate_phenotypes.module index 00eabdbf..8ab61405 100644 --- a/trpcultivate_phenotypes/trpcultivate_phenotypes.module +++ b/trpcultivate_phenotypes/trpcultivate_phenotypes.module @@ -11,23 +11,23 @@ use Drupal\Core\Routing\RouteMatchInterface; * Implements hook_help(). */ function trpcultivate_phenotypes_help($route_name, RouteMatchInterface $route_match) { + switch ($route_name) { // Provides the module overview in the help tab. case 'help.page.trpcultivate_phenotypes': $output = ''; $output .= '

' . t('About') . '

'; - $output .= ''; return $output; @@ -37,6 +37,7 @@ function trpcultivate_phenotypes_help($route_name, RouteMatchInterface $route_ma /** * Tripal Job callback. + * * Job registered during install to insert terms used by configuration * page default field values. * @@ -60,7 +61,7 @@ function trpcultivate_phenotypes_install_ontologyterms() { /** * Implements hook_theme(). * - * @see templates in /templates. + * @see /templates */ function trpcultivate_phenotypes_theme($existing, $type, $theme, $path) { $items = []; @@ -72,9 +73,9 @@ function trpcultivate_phenotypes_theme($existing, $type, $theme, $path) { 'data' => [ 'headers' => [], 'template_file' => '#', - ] + ], ], - 'template' => 'trpcultivate-phenotypes-template-importer-header' + 'template' => 'trpcultivate-phenotypes-template-importer-header', ], // Theme instructions found in the header section // of ontology configuration page. @@ -83,17 +84,17 @@ function trpcultivate_phenotypes_theme($existing, $type, $theme, $path) { 'data' => [ 'section' => '', 'link_01' => '', - 'link_02' => '' - ] + 'link_02' => '', + ], ], - 'template' => 'trpcultivate-phenotypes-template-header-instructions' + 'template' => 'trpcultivate-phenotypes-template-header-instructions', ], // Theme validation result window of an importer. 'result_window' => [ 'variables' => [ - 'data' => [] + 'data' => [], ], - 'template' => 'trpcultivate-phenotypes-template-result-window' + 'template' => 'trpcultivate-phenotypes-template-result-window', ], ]; diff --git a/trpcultivate_phenotypes/trpcultivate_phenotypes.services.yml b/trpcultivate_phenotypes/trpcultivate_phenotypes.services.yml index 2e05ffc0..2d48acc0 100644 --- a/trpcultivate_phenotypes/trpcultivate_phenotypes.services.yml +++ b/trpcultivate_phenotypes/trpcultivate_phenotypes.services.yml @@ -2,7 +2,7 @@ services: trpcultivate_phenotypes.terms: class: 'Drupal\trpcultivate_phenotypes\Service\TripalCultivatePhenotypesTermsService' - arguments: ['@config.factory', '@tripal.logger'] + arguments: ['@config.factory', '@tripal.logger', '@tripal_chado.database'] trpcultivate_phenotypes.genus_ontology: class: 'Drupal\trpcultivate_phenotypes\Service\TripalCultivatePhenotypesGenusOntologyService'