3 changed files with 361 additions and 0 deletions
@ -0,0 +1,31 @@
|
||||
# DOI Prefill |
||||
|
||||
Allows users create Drupal nodes with data retrieved from Crossref. |
||||
|
||||
## Installation |
||||
|
||||
Install as |
||||
[usual](https://www.drupal.org/docs/extending-drupal/installing-modules). |
||||
|
||||
## Configuration |
||||
|
||||
The form at `admin/config/system/doi_field_setting`s allows you to map the fields returned by Crossref to fields |
||||
in your Islandora installation e.g. Crossref's `Contributors` field can be mapped to `field_contributor`, or `field_linked_agent`. |
||||
|
||||
You may optionally map the Crossref genre fields to your own taxonomy term e.g. `journal-article` to `Journal Article` |
||||
|
||||
## Usage |
||||
|
||||
After installing and enabling and configuring the module add a link to `doi-prefill/doi-prepopulate` in your [Shortcuts menu](admin/config/user-interface/shortcut/manage/default/customize) |
||||
|
||||
Navigate to the form where you can enter a DOI, a collection for your new node, and choose whether you'd like to be taken the node's edit form or be returned to the same page. |
||||
|
||||
|
||||
|
||||
## Maintainers |
||||
Current maintainers: |
||||
|
||||
* [Robertson Library](https://library.upei.ca/) |
||||
|
||||
## License |
||||
[GPLv3](http://www.gnu.org/licenses/gpl-3.0.txt) |
||||
@ -0,0 +1,6 @@
|
||||
doi_prefill.doi_settings: |
||||
title: DOI Prefill Settings |
||||
description: Configure DOI mappings |
||||
parent: system.admin_config_system |
||||
route_name: doi_prefill.doi_settings |
||||
weight: 10 |
||||
@ -0,0 +1,324 @@
|
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace Drupal\doi_prefill\Form; |
||||
|
||||
use Drupal\Core\Form\ConfigFormBase; |
||||
use Drupal\Core\Form\FormStateInterface; |
||||
use Drupal\Core\Entity\EntityFieldManagerInterface; |
||||
use Drupal\Core\Entity\EntityTypeManagerInterface; |
||||
use Symfony\Component\DependencyInjection\ContainerInterface; |
||||
use Drupal\field\Entity\FieldConfig; |
||||
use Drupal\node\Entity\NodeType; |
||||
use Drupal\islandora\IslandoraUtils; |
||||
|
||||
/** |
||||
* Configure DOI Prefill settings for this site. |
||||
*/ |
||||
final class DOIFieldSettingsForm extends ConfigFormBase { |
||||
|
||||
/** |
||||
* The entity field manager service. |
||||
* |
||||
* @var \Drupal\Core\Entity\EntityFieldManagerInterface |
||||
*/ |
||||
protected $entityFieldManager; |
||||
|
||||
/** |
||||
* Islandora utility functions. |
||||
* |
||||
* @var \Drupal\islandora\IslandoraUtils |
||||
*/ |
||||
protected $utils; |
||||
|
||||
/** |
||||
* The entity type manager service. |
||||
* |
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface |
||||
*/ |
||||
protected $entityTypeManager; |
||||
|
||||
/** |
||||
* Constructs a new DOIFieldSettingsForm. |
||||
* |
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager |
||||
* The entity type manager service. |
||||
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entityFieldManager |
||||
* THe field manager. |
||||
*/ |
||||
public function __construct(EntityTypeManagerInterface $entityTypeManager, EntityFieldManagerInterface $entityFieldManager, IslandoraUtils $utils) { |
||||
$this->entityTypeManager = $entityTypeManager; |
||||
$this->entityFieldManager = $entityFieldManager; |
||||
$this->utils = $utils; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
*/ |
||||
public static function create(ContainerInterface $container) { |
||||
return new static( |
||||
$container->get('entity_type.manager'), |
||||
$container->get('entity_field.manager'), |
||||
$container->get('islandora.utils'), |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
*/ |
||||
public function getFormId(): string { |
||||
return 'doi_prefill_doi_field_settings'; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
*/ |
||||
protected function getEditableConfigNames(): array { |
||||
return ['doi_prefill.settings']; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
*/ |
||||
public function buildForm(array $form, FormStateInterface $form_state): array { |
||||
$doi_fields = [ |
||||
'title' => 'Title', |
||||
'contributors' => 'Contributors', |
||||
'publisher' => 'Publisher', |
||||
'doi' => 'DOI', |
||||
'genre' => 'Genre', |
||||
'issue' => 'Issue', |
||||
'volume' => 'Volume', |
||||
'date_issued' => 'Date issued', |
||||
'abstract' => 'Abstract', |
||||
'host_title' => 'Host title', |
||||
'date_online' => 'Date online', |
||||
'page_range' => 'Page range', |
||||
'series_issn' => 'Series ISSN', |
||||
]; |
||||
|
||||
$config = $this->config('doi_prefill.settings'); |
||||
$fields = $this->entityFieldManager->getFieldDefinitions('node', 'islandora_object'); |
||||
$field_options = ['title' => 'Title']; |
||||
foreach ($fields as $field) { |
||||
if ($field instanceof FieldConfig) { |
||||
$label = (string) $field->getLabel(); |
||||
$name = $field->getName(); |
||||
$field_options[$name] = $label; |
||||
} |
||||
} |
||||
asort($field_options); |
||||
$content_types = NodeType::loadMultiple(); |
||||
$destination_content_types = []; |
||||
foreach ($content_types as $type) { |
||||
if ($this->utils->isIslandoraType('node', $type->id())) { |
||||
$destination_content_types[$type->id()] = $type->label(); |
||||
} |
||||
} |
||||
|
||||
$form['content_type'] = [ |
||||
'#type' => 'select', |
||||
'#title' => $this->t('Content Type'), |
||||
'#description' => $this->t("Choose content type for new node"), |
||||
'#options' => $destination_content_types, |
||||
'#default_value' => $config->get('content_type'), |
||||
]; |
||||
|
||||
// Display fields in a table format. |
||||
$form['description'] = [ |
||||
'#type' => 'markup', |
||||
'#markup' => $this->t('DOI fields are returned by Crossref. Please choose field from your Islandora Installation to hold the returned value.'), |
||||
]; |
||||
|
||||
$form['field_table'] = [ |
||||
'#type' => 'table', |
||||
'#header' => [ |
||||
$this->t('DOI Field'), |
||||
$this->t('Islandora Field'), |
||||
], |
||||
'#prefix' => '<div id="field-table-wrapper">', |
||||
'#suffix' => '</div>', |
||||
]; |
||||
foreach ($doi_fields as $machine_name => $field) { |
||||
$form['field_table'][$machine_name]['field_name'] = [ |
||||
'#plain_text' => $field, |
||||
]; |
||||
|
||||
// Add a dropdown for each field. |
||||
$form['field_table'][$machine_name]['dropdown'] = [ |
||||
'#type' => 'select', |
||||
'#options' => $field_options, |
||||
'#default_value' => $config->get('field_settings')[$machine_name] ?? '', |
||||
]; |
||||
} |
||||
$form['#attached']['library'][] = 'doi_prefill/doi_field_selector_styles'; |
||||
|
||||
$form['pairs_description'] = [ |
||||
'#type' => 'markup', |
||||
'#markup' => $this->t('DOI genre terms are returned by Crossref. Please choose any term you would like to replace from your own taxonomy.'), |
||||
]; |
||||
|
||||
$doi_term_islandora_term_pairs = $form_state->get('doi_term_islandora_term_pairs'); |
||||
if (!$doi_term_islandora_term_pairs) { |
||||
$doi_term_islandora_term_pairs = $config->get('doi_term_islandora_term_pairs'); |
||||
} |
||||
if (empty($doi_term_islandora_term_pairs)) { |
||||
// Initialize as an empty array if no pairs exist. |
||||
$doi_term_islandora_term_pairs = []; |
||||
} |
||||
|
||||
// Set the form state for entry_count and doi_term_islandora_term_pairs. |
||||
$form_state->set('doi_term_islandora_term_pairs', $doi_term_islandora_term_pairs); |
||||
$entry_count = count($doi_term_islandora_term_pairs); |
||||
$form_state->set('entry_count', $entry_count); |
||||
|
||||
// Define the table structure for key-value pairs. |
||||
$form['doi_term_islandora_term_pairs'] = [ |
||||
'#type' => 'table', |
||||
'#prefix' => '<div id="key-value-pairs-wrapper">', |
||||
'#suffix' => '</div>', |
||||
]; |
||||
|
||||
// Generate the table rows dynamically based on stored pairs. |
||||
foreach ($doi_term_islandora_term_pairs as $entry_id => $pair) { |
||||
$pair['entry_id'] = $entry_id; |
||||
$unique_id = $pair['entry_id'] ?? uniqid(); |
||||
$form['doi_term_islandora_term_pairs'][$unique_id]['key'] = [ |
||||
'#type' => 'textfield', |
||||
'#default_value' => $pair['key'] ?? '', |
||||
'#title' => $this->t('term from DOI'), |
||||
'#required' => TRUE, |
||||
]; |
||||
|
||||
$form['doi_term_islandora_term_pairs'][$unique_id]['value'] = [ |
||||
'#type' => 'textfield', |
||||
'#default_value' => $pair['value'] ?? '', |
||||
'#title' => $this->t('Genre term'), |
||||
'#required' => TRUE, |
||||
]; |
||||
|
||||
// Hidden field to store the correct entry ID. |
||||
$form['doi_term_islandora_term_pairs'][$unique_id]['entry_id'] = [ |
||||
'#type' => 'hidden', |
||||
'#value' => $entry_id, |
||||
]; |
||||
|
||||
// Remove button for each entry. |
||||
$form['doi_term_islandora_term_pairs'][$unique_id]['remove'] = [ |
||||
'#type' => 'submit', |
||||
'#value' => $this->t('Remove'), |
||||
'#submit' => ['::removeCallback'], |
||||
'#limit_validation_errors' => [], |
||||
'#ajax' => [ |
||||
'callback' => '::ajaxCallback', |
||||
'wrapper' => 'key-value-pairs-wrapper', |
||||
], |
||||
// Instead of relying on `#attributes`, set a unique `#name`! |
||||
'#name' => 'remove_' . $unique_id, |
||||
]; |
||||
|
||||
} |
||||
|
||||
// Button to add another key-value pair. |
||||
$form['add_more'] = [ |
||||
'#type' => 'submit', |
||||
'#value' => $this->t('Add term'), |
||||
'#submit' => ['::addMoreCallback'], |
||||
'#ajax' => [ |
||||
'callback' => '::ajaxCallback', |
||||
'wrapper' => 'key-value-pairs-wrapper', |
||||
], |
||||
]; |
||||
|
||||
// Submit button for the form. |
||||
$form['submit'] = [ |
||||
'#type' => 'submit', |
||||
'#value' => $this->t('Save term mappings'), |
||||
]; |
||||
|
||||
return parent::buildForm($form, $form_state); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritdoc} |
||||
*/ |
||||
public function submitForm(array &$form, FormStateInterface $form_state): void { |
||||
if (!empty($form_state->getValue('field_table'))) { |
||||
foreach ($form_state->getValue('field_table') as $doi_field => $islandora_field) { |
||||
$field_settings[$doi_field] = $islandora_field['dropdown']; |
||||
} |
||||
} |
||||
$doi_term_islandora_term_pairs = $form_state->getValue('doi_term_islandora_term_pairs'); |
||||
$content_type = $form_state->getValue('content_type'); |
||||
$this->config('doi_prefill.settings') |
||||
->set('field_settings', $field_settings) |
||||
->set('doi_term_islandora_term_pairs', $doi_term_islandora_term_pairs) |
||||
->set('content_type', $content_type) |
||||
->save(); |
||||
parent::submitForm($form, $form_state); |
||||
} |
||||
|
||||
/** |
||||
* AJAX callback to refresh the form. |
||||
*/ |
||||
public function ajaxCallback(array &$form, FormStateInterface $form_state) { |
||||
return $form['doi_term_islandora_term_pairs']; |
||||
} |
||||
|
||||
/** |
||||
* Adds more key-value pair fields. |
||||
*/ |
||||
public function addMoreCallback(array &$form, FormStateInterface $form_state) { |
||||
// Retrieve existing key-value pairs. |
||||
$doi_term_islandora_term_pairs = $form_state->get('doi_term_islandora_term_pairs') ?? []; |
||||
|
||||
// Get submitted values and merge with stored ones. |
||||
$user_input = $form_state->getUserInput(); |
||||
if (!empty($user_input['doi_term_islandora_term_pairs'])) { |
||||
foreach ($user_input['doi_term_islandora_term_pairs'] as $id => $values) { |
||||
if (!isset($doi_term_islandora_term_pairs[$id])) { |
||||
$doi_term_islandora_term_pairs[$id] = $values; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Add a new empty entry with a unique ID. |
||||
$unique_id = uniqid(); |
||||
$doi_term_islandora_term_pairs[$unique_id] = [ |
||||
'key' => '', |
||||
'value' => '', |
||||
'unique_id' => $unique_id, |
||||
]; |
||||
|
||||
// Store the updated values. |
||||
$form_state->set('doi_term_islandora_term_pairs', $doi_term_islandora_term_pairs); |
||||
$form_state->set('entry_count', count($doi_term_islandora_term_pairs)); |
||||
|
||||
// Rebuild the form. |
||||
$form_state->setRebuild(); |
||||
} |
||||
|
||||
/** |
||||
* Remove chosen element. |
||||
*/ |
||||
public function removeCallback(array &$form, FormStateInterface $form_state) { |
||||
$triggering_element = $form_state->getTriggeringElement(); |
||||
// Using hidden field to get around Drupal's issues with ajax. |
||||
$button_name = $triggering_element['#name'] ?? ''; |
||||
|
||||
// Extract the unique ID from the button name. |
||||
if (preg_match('/remove_(.+)/', $button_name, $matches)) { |
||||
$clicked_id = $matches[1]; |
||||
} |
||||
$doi_term_islandora_term_pairs = $form_state->get('doi_term_islandora_term_pairs') ?? []; |
||||
|
||||
if (isset($doi_term_islandora_term_pairs[$clicked_id])) { |
||||
unset($doi_term_islandora_term_pairs[$clicked_id]); |
||||
} |
||||
$form_state->set('doi_term_islandora_term_pairs', $doi_term_islandora_term_pairs); |
||||
$form_state->set('entry_count', count($doi_term_islandora_term_pairs)); |
||||
$form_state->setRebuild(); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue