Skip to content

Commit

Permalink
Merge pull request #133 from TripalCultivate/g2.124-describeUploadFil…
Browse files Browse the repository at this point in the history
…eFormat

Updates file template generator service
  • Loading branch information
reynoldtan authored Jan 20, 2025
2 parents d7217c8 + aa83470 commit 32a7513
Show file tree
Hide file tree
Showing 5 changed files with 391 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
* label = @Translation("Tripal Cultivate: Phenotypic Trait Importer"),
* description = @Translation("Loads Traits for phenotypic data into the system. This is useful for large phenotypic datasets to ease the upload process."),
* file_types = {"tsv"},
* upload_description = @Translation("Please provide a txt or tsv data file."),
* upload_description = @Translation("Please provide a data file."),
* upload_title = @Translation("Phenotypic Trait Data File*"),
* use_analysis = FALSE,
* require_analysis = FALSE,
Expand Down Expand Up @@ -1541,29 +1541,60 @@ public function postRun() {
}

/**
* {@inheritdoc}
* Describe the upload format including column descriptions + template file.
*
* Class TripalImporterBase is the parent class of this method and additional
* documentation is available in reference link below.
*
* NOTE: This method supports full HTML markup output.
*
* All relevant information relating to expected column headers and usage
* notes are laid out using the theme 'importer_header'. This is rendered
* using the referenced TWIG file below.
*
* A template geneartor service is utilized to provide a downloadable file
* template, pre-configured to contain all headers required. The link to
* this template file is also formatted using the theme 'importer_header'.
*
* @return string
* The fully rendered HTML string produced by the 'importer_header' theme
* with the pertinent variables supplied by this method.
*
* @see Drupal\tripal\TripalImporter\TripalImporterBase::describeUploadFileFormat()
* @see templates\trpcultivate-phenotypes-template-importer-header.html.twig
*/
public function describeUploadFileFormat() {
// A template file has been generated and is ready for download.
$importer_id = $this->pluginDefinition['id'];

// Only the header names are needed for making the template file, so pull
// them out into a new array.
$column_headers = array_column($this->headers, 'name');

// File types 'file_types' annotation definition of this importer.
// The first item in the definition list will be used as the primary
// file extension of the template file.
// File MIME type and delimiter are based on mapping information defined
// in the validator base and file types validator trait.
$file_extensions = $this->plugin_definition['file_types'];

$file_link = $this->service_FileTemplate
->generateFile($importer_id, $column_headers);
->generateFile($importer_id, $column_headers, $file_extensions);

// Additional notes to the headers.
$notes = $this->t('The order of the above columns is important and your file must include a header!
If you have a single trait measured in more than one way (i.e. with multiple collection
methods), then you should have one line per collection method with the trait repeated.');
methods), then you should have one line per collection method with the trait name/description repeated.');

// Render the header notes/lists template and use the file link as
// Render the header and notes/lists in a template and use the file link as
// the value to href attribute of the link to download a template file.
$supported_file_extensions = implode(', ', $file_extensions);

$build = [
'#theme' => 'importer_header',
'#data' => [
'headers' => $this->headers,
'file_extensions' => $supported_file_extensions,
'notes' => $notes,
'template_file' => $file_link,
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,94 +1,137 @@
<?php

/**
* @file
* Tripal Cultivate Phenotypes File Template service definition.
*/

namespace Drupal\trpcultivate_phenotypes\Service;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\file\Entity\File;
use Drupal\trpcultivate_phenotypes\TripalCultivateValidator\ValidatorTraits\FileTypes;
use Drupal\trpcultivate_phenotypes\TripalCultivateValidator\TripalCultivatePhenotypesValidatorBase;

/**
* Class TripalCultivatePhenotypesFileTemplateService.
* Generate data collection template file used in the importer.
*/
class TripalCultivatePhenotypesFileTemplateService {
// Module configuration.

/**
* Validator Traits required by this validator.
*
* - FileTypes: Gets an array of all supported MIME types the importer is
* configured to process.
*
* @todo Update when/if $extension_to_mime_mapping is moved to a more generic
* class (ie. not validator specific).
*/
use FileTypes;

/**
* Module configuration.
*
* @var Drupal\Core\Config\ConfigFactoryInterface
*/
protected $config;

// Drupal current user.
/**
* Drupal user account.
*
* @var Drupal\Core\Session\AccountInterface
*/
protected $user;

/**
* Constructor.
*
* @param Drupal\Core\Config\ConfigFactoryInterface $config
* Configuration interface.
* @param Drupal\Core\Session\AccountInterface $user
* Account interface.
*/
public function __construct(ConfigFactoryInterface $config, AccountInterface $current_user) {
public function __construct(ConfigFactoryInterface $config, AccountInterface $user) {
// Set the configuration.
$this->config = $config->get('trpcultivate_phenotypes.settings');
$this->user = $current_user;

// Set the current user.
$this->user = $user;
}

/**
* Generate template file.
*
* @param string $importer_id
* String, The plugin ID annotation definition.
* String, The plugin ID annotation definition used to prefix the filename.
* @param array $column_headers
* Array keys (column headers) as defined by the header property in the importer.
* An array of column headers to be written into the template file as the
* column header row.
* @param array $file_extensions
* The file extension of the template file. This is taken from the
* 'file_type' plugin annotation definition of the Importer.
*
* NOTE: Only the first item is used as the primary file extension, in case
* of multiple file type values were provided.
*
* @return string
* The relative path to the generated template file.
*
* @return path
* Path to the template file.
* @see src/TripalCultivateValidator/TripalCultivatePhenotypesValidatorBase.php
* @see src/TripalCultivateValidator/ValidatorTraits/FileTypes.php
*/
public function generateFile($importer_id, $column_headers) {
// Fetch the configuration relating to directory for housing data collection template file.
// This directory had been setup during install and had / at the end as defined.
// @see config install and schema.
public function generateFile($importer_id, $column_headers, $file_extensions) {

// Fetch the configuration relating to directory for housing data collection
// template file. This directory had been setup during install and had / at
// the end as defined. @see config install and schema.
$dir_template_file = $this->config->get('trpcultivate.phenotypes.directory.template_file');

// About the template file:

// File extension.
$fileextension = 'tsv';
// MIME: TSV type file.
$filemime = 'text/tab-separated-values';

// Personalize the filename by appending display name of the current user, but first
// sanitize it by replacing all spaces into a dash character.
$file_extension = $file_extensions[0];
// See referenced file in the doc block about the mapping variables used.
// File MIME type.
// @todo Should move the following 2 methods to a more generic class
// instead of keeping them in FileTypes and ValidatorBase which are meant
// for validators.
$file_mime_type = self::$extension_to_mime_mapping[$file_extension];
// File delimiter.
$file_delimiter = TripalCultivatePhenotypesValidatorBase::$mime_to_delimiter_mapping[$file_mime_type[0]];

// Personalize the filename by appending display name of the current user,
// but first sanitize it by replacing all spaces into a dash character.
$display_name = $this->user->getDisplayName() ?? 'anonymous-user';
$user_display_name = str_replace(' ', '-', $display_name);

// Filename: importer id - data collection template file - username . (TSV).
$filename = $importer_id . '-data-collection-template-file-' . $user_display_name . '.' . $fileextension;
$filename = $importer_id . '-data-collection-template-file-' . $user_display_name . '.' . $file_extension;

// Create the file.
$file = File::create([
'filename' => $filename,
'filemime' => $filemime,
'uri' => $dir_template_file . $filename
'filemime' => $file_mime_type,
'uri' => $dir_template_file . $filename,
]);

// Mark file for deletion during a Drupal maintenance.
$file->set('status', 0);
// Save.
$file->save();

// Write the contents: headers into the file created and serve the path back
// to the calling Importer as value to the href attribute of link to download a template file.

// File uri of the created file.
// to the calling Importer as value to the href attribute of link to
// download a template file. File uri of the created file.
$fileuri = $file->getFileUri();

// Before we can write contents, we need to ensure the upper level folders exist.
// Before we can write contents, we need to ensure the upper level
// folders exist.
if (!file_exists($dir_template_file)) {
mkdir($dir_template_file, 0777, true);
mkdir($dir_template_file, 0777, TRUE);
}

// Convert the headers array into a tsv string value and post into the first line of the file.
$fileheaders = implode("\t", $column_headers) . "\n# DELETE THIS LINE --- START DATA HERE AND USE TAB KEY #";
// Convert the headers array into a delimited string value and post into the
// first line of the file.
$fileheaders = implode($file_delimiter[0], $column_headers) . "\n# DELETE THIS LINE --- START DATA HERE AND USE APPROPRIATE DELIMITER/VALUE SEPARATOR #";
file_put_contents($fileuri, $fileheaders);

// Save.
$file->save();

return $file->createFileUrl();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
{{ attach_library('trpcultivate_phenotypes/trpcultivate-phenotypes-style-importer-header') }}

<div id="tcp-header-notes">
<p>This should be a tab-separated file with the following columns:</p>
<p>This should be a [{{data.file_extensions}}] file with the following columns:</p>

<ol id="tcp-header-notes">
{% for header in data.headers %}
Expand All @@ -21,6 +21,8 @@
</li>
{% endfor %}
</ol>

<p><em>{{data.notes}}</em></p>
</div>

<div id="tcp-template-file">
Expand Down
Loading

0 comments on commit 32a7513

Please sign in to comment.