Browse Source

initial commit

main
ajstanley 11 months ago
commit
b795062ca0
  1. 13
      css/doi_prefill.css
  2. 8
      doi_prefill.info.yml
  3. 5
      doi_prefill.libraries.yml
  4. 6
      doi_prefill.module
  5. 7
      doi_prefill.routing.yml
  6. 4
      doi_prefill.services.yml
  7. 55
      src/CrossrefApiReader.php
  8. 227
      src/Form/DoiPrepopulateForm.php

13
css/doi_prefill.css

@ -0,0 +1,13 @@
.form-inline {
display: flex;
gap: 20px;
flex-wrap: wrap;
max-width: 100%;
justify-content: space-evenly;
}
.form-inline .form-item {
flex: 1;
min-width: 250px;
}

8
doi_prefill.info.yml

@ -0,0 +1,8 @@
name: 'DOI Prefill'
type: module
description: 'Generates Link to Prepopulate DOI ingest form'
package: Custom
core_version_requirement: ^10 || ^11
dependencies:
- islandora:islandora
- prepopulate:prepopulate

5
doi_prefill.libraries.yml

@ -0,0 +1,5 @@
styles:
version: 1.x
css:
theme:
css/doi_prefill.css: {}

6
doi_prefill.module

@ -0,0 +1,6 @@
<?php
/**
* @file
* Primary module hooks for DOI Prefill module.
*/

7
doi_prefill.routing.yml

@ -0,0 +1,7 @@
doi_prefill.doi_prepopulate:
path: '/doi-prefill/doi-prepopulate'
defaults:
_title: 'Doi Prepopulate'
_form: 'Drupal\doi_prefill\Form\DoiPrepopulateForm'
requirements:
_permission: 'create islandora_object content'

4
doi_prefill.services.yml

@ -0,0 +1,4 @@
services:
doi_prefill.crossref_api_reader:
class: Drupal\doi_prefill\CrossrefApiReader
arguments: ['@http_client', '@logger.channel.islandora', '@config.factory']

55
src/CrossrefApiReader.php

@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace Drupal\doi_prefill;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Psr\Http\Client\ClientInterface;
/**
* Simple API class to read Crossref.
*
* See https://api.crossref.org/swagger-ui/index.html#/
*/
final class CrossrefApiReader {
/**
* Constructs a CrossrefApiReader object.
*/
public function __construct(
private readonly ClientInterface $httpClient,
private readonly LoggerChannelInterface $loggerChannelIslandora,
private readonly ConfigFactoryInterface $configFactory,
) {}
/**
* Returns Crossref data from DOI.
*/
public function getWork($identifier) {
$site_email = $this->configFactory->get('system.site')->get('mail');
$endpoint = 'https://api.crossref.org/works';
$encoded_doi = urlencode($identifier);
$url = "{$endpoint}/{$encoded_doi}";
try {
$response = $this->httpClient->get($url, [
'headers' => [
'accept' => 'application/json',
'User-Agent' => 'YourProjectName/1.0 (mailto:your-email@example.com)',
'User-Agent' => "IslandScholar/ (mailto:{$site_email})",
],
]);
$data = $response->getBody()->getContents();
$values = json_decode($data, TRUE);
return $values['message'];
}
catch (\Exception $e) {
$this->loggerChannelIslandora->error('Failed to fetch citation from CrossRef: ' . $e->getMessage());
return NULL;
}
}
}

227
src/Form/DoiPrepopulateForm.php

@ -0,0 +1,227 @@
<?php
declare(strict_types=1);
namespace Drupal\doi_prefill\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\doi_prefill\CrossrefApiReader;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\node\Entity\Node;
use Drupal\taxonomy\Entity\Term;
use Drupal\Core\Entity\EntityTypeManagerInterface;
/**
* Provides a DOI Prefill form.
*/
final class DoiPrepopulateForm extends FormBase {
/**
* The DOI API reader.
*
* @var \Drupal\doi_prefill\CrossrefApiReader
*/
protected $doiApi;
/**
* The entity type manager service.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The constructor.
*
* @param \Drupal\doi_prefill\CrossrefApiReader $doiApi
*/
public function __construct(CrossrefApiReader $doiApi, EntityTypeManagerInterface $entityTypeManager) {
$this->doiApi = $doiApi;
$this->entityTypeManager = $entityTypeManager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
// Instantiates this form class.
return new static(
// Load the service required to construct this class.
$container->get('doi_prefill.crossref_api_reader'),
$container->get('entity_type.manager')
);
}
/**
* {@inheritdoc}
*/
public function getFormId(): string {
return 'doi_prefill_doi_prepopulate';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state): array {
$terms = $this->entityTypeManager->getStorage('taxonomy_term')->loadByProperties([
'name' => 'Collection',
'vid' => 'islandora_models',
]);
$term = reset($terms);
$collection_ids = \Drupal::entityQuery('node')
->accessCheck(FALSE)
->condition('field_model', $term->id())
->execute();
$collections = $this->entityTypeManager->getStorage('node')->loadMultiple($collection_ids);
$options = [];
foreach ($collections as $id => $collection) {
$options[$id] = $collection->label();
}
$form['container'] = [
'#type' => 'container',
'#attributes' => ['class' => ['form-inline']],
];
$form['container']['doi'] = [
'#type' => 'textfield',
'#title' => $this->t('Enter DOI'),
'#required' => TRUE,
];
$form['container']['collection'] = [
'#title' => $this->t('Collection'),
'#type' => 'select',
'#options' => $options,
'#required' => TRUE,
];
$form['container']['redirect'] = [
'#type' => 'select',
'#title' => $this->t("After submission?"),
'#options' => [
'edit' => $this->t('Edit after submission'),
'resume' => $this->t('Return to this form'),
],
'#default_value' => 'edit',
];
$form['#attached']['library'][] = 'doi_prefill/styles';
$form['actions'] = [
'#type' => 'actions',
'submit' => [
'#type' => 'submit',
'#value' => $this->t('Send'),
],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state): void {
$doi = trim($form_state->getValue('doi'));
$collection = $form_state->getValue('collection');
$contents = $this->doiApi->getWork($doi);
// Build typed relations.
$typed_relations = [];
$vid = 'person';
foreach ($contents['author'] as $author) {
$author_term = "{$author['family']}";
if (isset($author['given'])) {
$author_term = "{$author_term}, {$author['given']}";
}
$term = $this->getOrCreateTerm($author_term, $vid);
$typed_relations[] = [
'target_id' => $term->id(),
'rel_type' => 'relators:aut',
];
}
$genre = $this->getOrCreateTerm($contents['type'], 'genre');
// Build new node.
$new_node = Node::create([
'title' => $contents['title'][0],
'field_member_of' => $collection,
'type' => 'islandora_object',
'field_linked_agent' => $typed_relations,
'field_publisher' => $contents['publisher'],
'field_doi' => $doi,
'field_genre' => $genre->id(),
'field_issue' => $contents['issue'],
'field_volume' => $contents['volume'],
]);
// Optional fields.
if (isset($contents['abstract'])) {
$new_node->set('field_abstract', [
'value' => $contents['abstract'],
'format' => 'basic_html',
]);
}
if (isset($contents['published-online'])) {
$field_date_online = [];
foreach ($contents['published-online']['date-parts'] as $date_parts) {
$field_date_online[] = ['value' => implode('-', $date_parts)];
}
$new_node->set('field_date_online', $field_date_online);
}
// Multivalued fields.
$field_edtf_date_issued = [];
foreach ($contents['created']['date-parts'] as $date_parts) {
$field_edtf_date_issued[] = ['value' => implode('-', $date_parts)];
}
$new_node->set('field_edtf_date_issued', $field_edtf_date_issued);
$field_issn = [];
foreach ($contents['ISSN'] as $issn) {
$field_issn[] = ['value' => $issn];
}
$new_node->set('field_issn', $field_issn);
$new_node->save();
if ($form_state->getValue('redirect') == 'edit') {
$destination = "/node/{$new_node->id()}/edit";
$response = new RedirectResponse($destination);
$response->send();
}
}
/**
* Check if a term exists in a vocabulary. If not, create it.
*
* @param string $term_name
* The name of the term.
* @param string $vocabulary
* The machine name of the vocabulary.
*
* @return \Drupal\taxonomy\Entity\Term|null
* The term entity if found or created, or NULL on failure.
*/
public function getOrCreateTerm($term_name, $vocabulary) {
$terms = $this->entityTypeManager->getStorage('taxonomy_term')->loadByProperties([
'name' => $term_name,
'vid' => $vocabulary,
]);
if ($terms) {
// Return the first found term.
return reset($terms);
}
// If the term does not exist, create it.
$term = Term::create([
'name' => $term_name,
'vid' => $vocabulary,
]);
$term->save();
return $term;
}
}
Loading…
Cancel
Save