diff --git a/doi_prefill.services.yml b/doi_prefill.services.yml index c81e5a0..dacd1b3 100644 --- a/doi_prefill.services.yml +++ b/doi_prefill.services.yml @@ -2,3 +2,7 @@ services: doi_prefill.crossref_api_reader: class: Drupal\doi_prefill\CrossrefApiReader arguments: ['@http_client', '@logger.channel.islandora', '@config.factory'] + + doi_prefill.node_builder: + class: Drupal\doi_prefill\NodeBuilder + arguments: ['@entity_type.manager', '@doi_prefill.crossref_api_reader'] diff --git a/src/Form/DoiPrepopulateForm.php b/src/Form/DoiPrepopulateForm.php index bfd2fd8..ab8062c 100644 --- a/src/Form/DoiPrepopulateForm.php +++ b/src/Form/DoiPrepopulateForm.php @@ -7,10 +7,9 @@ namespace Drupal\doi_prefill\Form; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; -use Drupal\node\Entity\Node; -use Drupal\taxonomy\Entity\Term; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\doi_prefill\CrossrefApiReader; +use Drupal\doi_prefill\NodeBuilder; use Symfony\Component\HttpFoundation\RedirectResponse; /** @@ -25,6 +24,13 @@ final class DoiPrepopulateForm extends FormBase { */ protected $doiApi; + /** + * The Node builder. + * + * @var Drupal\doi_prefill\NodeBuilder + */ + protected $nodeBuilder; + /** * The entity type manager service. * @@ -40,9 +46,10 @@ final class DoiPrepopulateForm extends FormBase { * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager * The EntityTypeManager. */ - public function __construct(CrossrefApiReader $doiApi, EntityTypeManagerInterface $entityTypeManager) { + public function __construct(CrossrefApiReader $doiApi, EntityTypeManagerInterface $entityTypeManager, NodeBuilder $nodeBuilder) { $this->doiApi = $doiApi; $this->entityTypeManager = $entityTypeManager; + $this->nodeBuilder = $nodeBuilder; } /** @@ -53,7 +60,8 @@ final class DoiPrepopulateForm extends FormBase { return new static( // Load the service required to construct this class. $container->get('doi_prefill.crossref_api_reader'), - $container->get('entity_type.manager') + $container->get('entity_type.manager'), + $container->get('doi_prefill.node_builder') ); } @@ -127,103 +135,13 @@ final class DoiPrepopulateForm extends FormBase { 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_contributors' => $typed_relations, - 'field_publisher' => $contents['publisher'] ?? '', - 'field_doi' => $doi, - 'field_genre' => $genre->id(), - 'field_issue' => $contents['issue'] ?? '', - 'field_volume' => $contents['volume'] ?? '', - ]); + $nid = $this->nodeBuilder->buildNode($collection, $doi); - // 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_date_issued = []; - foreach (($contents['created']['date-parts'] ?? []) as $date_parts) { - $field_date_issued[] = ['value' => implode('-', $date_parts)]; - } - $new_node->set('field_date_issued', $field_date_issued); - - $field_series_issn = []; - foreach (($contents['ISSN'] ?? []) as $issn) { - $field_series_issn[] = ['value' => $issn]; - } - $new_node->set('field_series_issn', $field_series_issn); - $new_node->save(); if ($form_state->getValue('redirect') == 'edit') { - $destination = "/node/{$new_node->id()}/edit"; + $destination = "/node/{$nid}/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; - } } diff --git a/src/NodeBuilder.php b/src/NodeBuilder.php new file mode 100644 index 0000000..beb110d --- /dev/null +++ b/src/NodeBuilder.php @@ -0,0 +1,143 @@ + 'Journal Article', + 'book-chapter' => 'Book, Section', + 'monograph' => 'Book', + 'proceedings-article' => 'Conference Proceedings', + ]; + + /** + * Constructs a CrossrefApiReader object. + */ + public function __construct( + private readonly EntityTypeManager $entityTypeManager, + private readonly CrossrefApiReader $doiApi, + ) {} + + /** + * Builds and saves new node. + * + * @param int $collection + * The node ID of the collection. + * @param string $doi + * The DOI URL associated with the content. + * + * @return string + * The id of new node. + */ + public function buildNode($collection, $doi) { + $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_contributors' => $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_date_issued = []; + foreach (($contents['created']['date-parts'] ?? []) as $date_parts) { + $field_date_issued[] = ['value' => implode('-', $date_parts)]; + } + $new_node->set('field_date_issued', $field_date_issued); + + $field_series_issn = []; + foreach (($contents['ISSN'] ?? []) as $issn) { + $field_series_issn[] = ['value' => $issn]; + } + $new_node->set('field_series_issn', $field_series_issn); + $new_node->save(); + + return $new_node->id(); + } + + /** + * 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; + + } + +}