Skip to content

Commit 1cca0b8

Browse files
Merge branch 'externalDatasetsRelation340-906' into 'main'
Adiciona datasets externos à exportação Crossref - 3.4.0 See merge request softwares-pkp/plugins_ojs/dataverse!222
2 parents 021bbd6 + a030ea0 commit 1cca0b8

13 files changed

Lines changed: 183 additions & 101 deletions

classes/CrossrefXmlEditor.php

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@
44

55
use DOMDocument;
66
use DOMElement;
7-
use Illuminate\Support\Facades\DB;
87
use APP\plugins\generic\dataverse\classes\facades\Repo;
8+
use APP\plugins\generic\dataverse\classes\DataverseDAO;
99
use APP\plugins\generic\dataverse\dataverseAPI\actions\DatasetActions;
10+
use APP\plugins\generic\dataverse\classes\services\DataStatementService;
1011
use APP\plugins\generic\dataverse\classes\exception\DataverseException;
1112

1213
class CrossrefXmlEditor
1314
{
1415
private const RELATIONS_NAMESPACE = 'http://www.crossref.org/relations.xsd';
16+
private const ID_TYPE_DOI = 'doi';
17+
private const ID_TYPE_URL = 'uri';
1518

1619
private DatasetActions $datasetActions;
1720

@@ -27,17 +30,13 @@ public function addDatasetRelationToDepositXml(DOMDocument $depositXml): DOMDocu
2730
$submissionNodes = $depositXml->getElementsByTagName('posted_content');
2831
}
2932

33+
$dataverseDao = new DataverseDAO();
3034
foreach ($submissionNodes as $submissionNode) {
3135
$doiDataNode = $submissionNode->getElementsByTagName('doi_data')->item(0);
3236
$doiNode = $doiDataNode->getElementsByTagName('doi')->item(0);
3337
$doi = $doiNode->nodeValue;
3438

35-
$submissionId = DB::table('submissions as s')
36-
->leftJoin('publications as p', 'p.submission_id', '=', 's.submission_id')
37-
->leftJoin('dois as d', 'd.doi_id', '=', 'p.doi_id')
38-
->where('d.doi', '=', $doi)
39-
->value('s.submission_id');
40-
39+
$submissionId = $dataverseDao->getSubmissionIdByDoi($doi);
4140
if (!$submissionId) {
4241
continue;
4342
}
@@ -57,28 +56,39 @@ public function addDatasetRelationToDepositXml(DOMDocument $depositXml): DOMDocu
5756
}
5857

5958
if ($dataset->isPublished()) {
60-
$this->addDatasetRelationToWorkNode($submissionNode, $study->getPersistentId());
59+
$doi = preg_replace('/^doi:/i', '', $study->getPersistentId());
60+
$this->addDatasetRelationToWorkNode($submissionNode, $doi);
61+
}
62+
63+
$dataStatementTypes = $dataverseDao->getSubmissionStatementTypes($submissionId);
64+
if (in_array(DataStatementService::DATA_STATEMENT_TYPE_REPO_AVAILABLE, $dataStatementTypes)) {
65+
$externalDatasets = $dataverseDao->getSubmissionExternalDatasets($submissionId);
66+
67+
foreach ($externalDatasets as $externalDatasetUrl) {
68+
$this->addDatasetRelationToWorkNode($submissionNode, $externalDatasetUrl, true);
69+
}
6170
}
6271
}
6372

6473
return $depositXml;
6574
}
6675

67-
public function addDatasetRelationToWorkNode(DOMElement $workNode, string $persistentId): DOMElement
76+
public function addDatasetRelationToWorkNode(DOMElement $workNode, string $identifier, bool $isExternalDataset = false): DOMElement
6877
{
6978
$doc = $workNode->ownerDocument;
7079

7180
$relatedItemNode = $doc->createElementNS(self::RELATIONS_NAMESPACE, 'related_item');
7281

82+
$descriptionText = $isExternalDataset
83+
? 'Dataset deposited in repository'
84+
: 'Dataset deposited in Dataverse repository.';
7385
$descriptionNode = $doc->createElementNS(self::RELATIONS_NAMESPACE, 'description');
74-
$descriptionNode->appendChild($doc->createTextNode('Dataset deposited in Dataverse repository.'));
75-
76-
$doi = preg_replace('/^doi:/i', '', $persistentId);
86+
$descriptionNode->appendChild($doc->createTextNode($descriptionText));
7787

7888
$interWorkRelationNode = $doc->createElementNS(self::RELATIONS_NAMESPACE, 'inter_work_relation');
7989
$interWorkRelationNode->setAttribute('relationship-type', 'isSupplementedBy');
80-
$interWorkRelationNode->setAttribute('identifier-type', 'doi');
81-
$interWorkRelationNode->appendChild($doc->createTextNode($doi));
90+
$interWorkRelationNode->setAttribute('identifier-type', ($isExternalDataset ? self::ID_TYPE_URL : self::ID_TYPE_DOI));
91+
$interWorkRelationNode->appendChild($doc->createTextNode($identifier));
8292

8393
$relatedItemNode->appendChild($descriptionNode);
8494
$relatedItemNode->appendChild($interWorkRelationNode);
@@ -88,6 +98,7 @@ public function addDatasetRelationToWorkNode(DOMElement $workNode, string $persi
8898
$existingProgramNodes->item(0)->appendChild($relatedItemNode);
8999
} else {
90100
$programNode = $doc->createElementNS(self::RELATIONS_NAMESPACE, 'program');
101+
$programNode->setAttribute('name', 'relations');
91102
$programNode->appendChild($relatedItemNode);
92103
$doiDataNode = $workNode->getElementsByTagName('doi_data')->item(0);
93104
$workNode->insertBefore($programNode, $doiDataNode);

classes/DataverseDAO.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace APP\plugins\generic\dataverse\classes;
4+
5+
use Illuminate\Support\Facades\DB;
6+
7+
class DataverseDAO
8+
{
9+
public function getSubmissionIdByDoi(string $doi): ?int
10+
{
11+
return DB::table('submissions as s')
12+
->leftJoin('publications as p', 'p.submission_id', '=', 's.submission_id')
13+
->leftJoin('dois as d', 'd.doi_id', '=', 'p.doi_id')
14+
->where('d.doi', '=', $doi)
15+
->value('s.submission_id');
16+
}
17+
18+
public function getSubmissionStatementTypes(int $submissionId): ?array
19+
{
20+
$dataStatementTypes = $this->getCurrentPublicationSettingValue($submissionId, 'dataStatementTypes') ?? '[]';
21+
return json_decode($dataStatementTypes, true);
22+
}
23+
24+
public function getSubmissionExternalDatasets(int $submissionId): ?array
25+
{
26+
$dataStatementUrls = $this->getCurrentPublicationSettingValue($submissionId, 'dataStatementUrls') ?? '[]';
27+
return json_decode($dataStatementUrls, true);
28+
}
29+
30+
private function getCurrentPublicationSettingValue(int $submissionId, string $settingName)
31+
{
32+
return DB::table('submissions as s')
33+
->leftJoin('publications as p', 's.current_publication_id', '=', 'p.publication_id')
34+
->leftJoin('publication_settings as ps', 'p.publication_id', '=', 'ps.publication_id')
35+
->where('s.submission_id', '=', $submissionId)
36+
->where('ps.setting_name', '=', $settingName)
37+
->value('ps.setting_value');
38+
}
39+
}

tests/CrossrefXmlEditorTest.php

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,30 @@
1010
use APP\plugins\generic\dataverse\classes\entities\Dataset;
1111
use APP\plugins\generic\dataverse\classes\facades\Repo;
1212
use APP\plugins\generic\dataverse\dataverseAPI\actions\DatasetActions;
13+
use APP\plugins\generic\dataverse\classes\services\DataStatementService;
1314
use APP\plugins\generic\dataverse\classes\dispatchers\DataStatementDispatcher;
1415
use APP\plugins\generic\dataverse\DataversePlugin;
1516

1617
class CrossrefXmlEditorTest extends DatabaseTestCase
1718
{
1819
private CrossrefXmlEditor $xmlEditor;
19-
private DOMDocument $doc;
2020
private $contextId = 1;
21-
private ?int $submissionId = null;
21+
private ?Submission $submission = null;
22+
private ?Publication $publication = null;
2223
private ?int $doiId = null;
2324
private string $doi = '10.1234/PublicKnowledge.17';
2425
private ?DataverseStudy $study = null;
2526
private ?Dataset $dataset = null;
2627
private string $persistentId = 'doi:10.5072/FK2/ABCDEF';
28+
private string $externalDatasetUrl = 'https://doi.org/10.1234/zenodo.98765';
2729

2830
public function setUp(): void
2931
{
3032
parent::setUp();
3133
$plugin = new DataversePlugin();
3234
$dispatcher = new DataStatementDispatcher($plugin);
3335

34-
$this->doc = $this->createTestXml();
35-
$this->submissionId = $this->createTestSubmission();
36+
$this->createTestSubmission();
3637
$this->study = $this->createDataverseStudy();
3738
$this->dataset = $this->createTestDataset();
3839
$this->xmlEditor = $this->createXmlEditor();
@@ -41,19 +42,15 @@ public function setUp(): void
4142
public function tearDown(): void
4243
{
4344
parent::tearDown();
44-
45-
$submission = Repo::submission()->get($this->submissionId);
46-
if ($submission) {
47-
Repo::submission()->delete($submission);
48-
}
45+
Repo::submission()->delete($this->submission);
4946

5047
$doi = Repo::doi()->get($this->doiId);
5148
if ($doi) {
5249
Repo::doi()->delete($doi);
5350
}
5451
}
5552

56-
private function createTestSubmission(): int
53+
private function createTestSubmission()
5754
{
5855
$context = Application::getContextDAO()->getById($this->contextId);
5956

@@ -62,7 +59,7 @@ private function createTestSubmission(): int
6259
$publication = new Publication();
6360

6461
$submissionId = Repo::submission()->add($submission, $publication, $context);
65-
$submission = Repo::submission()->get($submissionId);
62+
$this->submission = Repo::submission()->get($submissionId);
6663

6764
$doi = Repo::doi()->newDataObject([
6865
'contextId' => $this->contextId,
@@ -71,17 +68,23 @@ private function createTestSubmission(): int
7168
]);
7269
$this->doiId = Repo::doi()->add($doi);
7370

74-
$publication = $submission->getCurrentPublication();
75-
$publication->setData('doiId', $this->doiId);
76-
Repo::publication()->dao->update($publication);
71+
$this->publication = $this->submission->getCurrentPublication();
72+
$this->publication->setData('doiId', $this->doiId);
73+
Repo::publication()->dao->update($this->publication);
74+
}
7775

78-
return $submissionId;
76+
private function addExternalDatasetsToPublication()
77+
{
78+
$this->publication->setData('dataStatementTypes', [DataStatementService::DATA_STATEMENT_TYPE_REPO_AVAILABLE]);
79+
$this->publication->setData('dataStatementUrls', [$this->externalDatasetUrl]);
80+
81+
Repo::publication()->dao->update($this->publication);
7982
}
8083

8184
private function createDataverseStudy(): DataverseStudy
8285
{
8386
$study = new DataverseStudy();
84-
$study->setSubmissionId($this->submissionId);
87+
$study->setSubmissionId($this->submission->getId());
8588
$study->setEditUri('https://demo.dataverse.org/dvn/api/data-deposit/v1.1/swordv2/edit/study/' . $this->persistentId);
8689
$study->setEditMediaUri('https://demo.dataverse.org/dvn/api/data-deposit/v1.1/swordv2/edit-media/study/' . $this->persistentId);
8790
$study->setStatementUri('https://demo.dataverse.org/dvn/api/data-deposit/v1.1/swordv2/statement/study/' . $this->persistentId);
@@ -94,10 +97,10 @@ private function createDataverseStudy(): DataverseStudy
9497
return $study;
9598
}
9699

97-
private function createTestXml()
100+
private function openTestXml(string $fixture): DOMDocument
98101
{
99102
$xml = new DOMDocument('1.0', 'UTF-8');
100-
$xml->appendChild($xml->createElement('work'));
103+
$xml->load(__DIR__ . '/fixtures/crossref/' . $fixture);
101104

102105
return $xml;
103106
}
@@ -121,37 +124,58 @@ private function createXmlEditor(): CrossrefXmlEditor
121124

122125
public function testAddsDatasetRelationToWorkNode(): void
123126
{
124-
$workNode = $this->doc->documentElement;
127+
$worksXml = $this->openTestXml('work_node.xml');
128+
$doi = preg_replace('/^doi:/i', '', $this->persistentId);
129+
130+
$noPreviousRelWorkNode = $worksXml->getElementsByTagName('work')->item(0);
131+
$this->xmlEditor->addDatasetRelationToWorkNode($noPreviousRelWorkNode, $doi);
132+
133+
$withPreviousRelWorkNode = $worksXml->getElementsByTagName('work')->item(1);
134+
$this->xmlEditor->addDatasetRelationToWorkNode($withPreviousRelWorkNode, $doi);
135+
136+
$resultXml = $worksXml->saveXML();
137+
$expectedXml = file_get_contents(__DIR__ . '/fixtures/crossref/expected/work_node.xml');
138+
139+
$this->assertXmlStringEqualsXmlString($expectedXml, $resultXml);
140+
}
141+
142+
public function testAddsExternalDatasetRelationToWorkNode(): void
143+
{
144+
$worksXml = $this->openTestXml('work_node.xml');
125145

126-
$result = $this->xmlEditor->addDatasetRelationToWorkNode($workNode, $this->persistentId);
146+
$noPreviousRelWorkNode = $worksXml->getElementsByTagName('work')->item(0);
147+
$this->xmlEditor->addDatasetRelationToWorkNode($noPreviousRelWorkNode, $this->externalDatasetUrl, true);
127148

128-
$programNode = $result->getElementsByTagNameNS('http://www.crossref.org/relations.xsd', 'program')->item(0);
129-
$resultXml = $result->ownerDocument->saveXML($programNode);
149+
$withPreviousRelWorkNode = $worksXml->getElementsByTagName('work')->item(1);
150+
$this->xmlEditor->addDatasetRelationToWorkNode($withPreviousRelWorkNode, $this->externalDatasetUrl, true);
130151

131-
$expectedXml = file_get_contents(__DIR__ . '/fixtures/crossref/expected/dataset_relation.xml');
152+
$resultXml = $worksXml->saveXML();
153+
$expectedXml = file_get_contents(__DIR__ . '/fixtures/crossref/expected/work_node_external.xml');
132154

133155
$this->assertXmlStringEqualsXmlString($expectedXml, $resultXml);
134156
}
135157

136158
public function testAddsDatasetRelationToDepositXml(): void
137159
{
138-
$this->assertAddingOfRelationToXmlMatchesExpected('preprint_deposit.xml');
139-
$this->assertAddingOfRelationToXmlMatchesExpected('article_deposit.xml');
160+
$this->assertAddingOfRelationToXmlMatchesExpected('preprint_deposit.xml', 'preprint_deposit.xml');
161+
$this->assertAddingOfRelationToXmlMatchesExpected('article_deposit.xml', 'article_deposit.xml');
140162
}
141163

142-
public function testAddsRelationToXmlAlreadyWithRelation(): void
164+
public function testAddsExternalDatasetRelationToDepositXml(): void
143165
{
144-
$this->assertAddingOfRelationToXmlMatchesExpected('preprint_deposit_with_relation.xml');
166+
$this->addExternalDatasetsToPublication();
167+
168+
$this->assertAddingOfRelationToXmlMatchesExpected('preprint_deposit.xml', 'preprint_deposit_external.xml');
145169
}
146170

147-
private function assertAddingOfRelationToXmlMatchesExpected(string $fixture): void
171+
private function assertAddingOfRelationToXmlMatchesExpected(string $fixture, string $expectedFixture): void
148172
{
149173
$depositXml = new DOMDocument();
150174
$depositXml->load(__DIR__ . '/fixtures/crossref/' . $fixture);
151175

152176
$result = $this->xmlEditor->addDatasetRelationToDepositXml($depositXml);
153177

154-
$expectedXml = file_get_contents(__DIR__ . '/fixtures/crossref/expected/' . $fixture);
178+
$expectedXml = file_get_contents(__DIR__ . '/fixtures/crossref/expected/' . $expectedFixture);
155179

156180
$this->assertXmlStringEqualsXmlString($expectedXml, $result->saveXML());
157181
}

tests/fixtures/crossref/expected/article_deposit.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
<day>18</day>
4747
<year>2023</year>
4848
</publication_date>
49-
<program xmlns="http://www.crossref.org/relations.xsd">
49+
<program xmlns="http://www.crossref.org/relations.xsd" name="relations">
5050
<related_item>
5151
<description>Dataset deposited in Dataverse repository.</description>
5252
<inter_work_relation relationship-type="isSupplementedBy" identifier-type="doi">10.5072/FK2/ABCDEF</inter_work_relation>

tests/fixtures/crossref/expected/dataset_relation.xml

Lines changed: 0 additions & 7 deletions
This file was deleted.

tests/fixtures/crossref/expected/preprint_deposit.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
<jats:abstract xmlns:jats="http://www.ncbi.nlm.nih.gov/JATS1" xml:lang="en">
2929
<jats:p>Lorem ipsum dolor sit amet...</jats:p>
3030
</jats:abstract>
31-
<rel:program>
31+
<rel:program name="relations">
3232
<rel:related_item>
3333
<rel:description>Dataset deposited in Dataverse repository.</rel:description>
3434
<rel:inter_work_relation relationship-type="isSupplementedBy" identifier-type="doi">10.5072/FK2/ABCDEF</rel:inter_work_relation>

tests/fixtures/crossref/expected/preprint_deposit_with_relation.xml renamed to tests/fixtures/crossref/expected/preprint_deposit_external.xml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,15 @@
2828
<jats:abstract xmlns:jats="http://www.ncbi.nlm.nih.gov/JATS1" xml:lang="en">
2929
<jats:p>Lorem ipsum dolor sit amet...</jats:p>
3030
</jats:abstract>
31-
<rel:program xmlns:rel="http://www.crossref.org/relations.xsd" name="relations">
32-
<rel:related_item>
33-
<rel:intra_work_relation relationship-type="isPreprintOf" identifier-type="doi">https://doi.org/10.1234/LepidusPeriodico.1756</rel:intra_work_relation>
34-
</rel:related_item>
31+
<rel:program name="relations">
3532
<rel:related_item>
3633
<rel:description>Dataset deposited in Dataverse repository.</rel:description>
3734
<rel:inter_work_relation relationship-type="isSupplementedBy" identifier-type="doi">10.5072/FK2/ABCDEF</rel:inter_work_relation>
3835
</rel:related_item>
36+
<rel:related_item>
37+
<rel:description>Dataset deposited in repository</rel:description>
38+
<rel:inter_work_relation relationship-type="isSupplementedBy" identifier-type="uri">https://doi.org/10.1234/zenodo.98765</rel:inter_work_relation>
39+
</rel:related_item>
3940
</rel:program>
4041
<doi_data>
4142
<doi>10.1234/PublicKnowledge.17</doi>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<works>
3+
<work> <!-- No previous relation -->
4+
<program xmlns="http://www.crossref.org/relations.xsd" name="relations">
5+
<related_item>
6+
<description>Dataset deposited in Dataverse repository.</description>
7+
<inter_work_relation relationship-type="isSupplementedBy" identifier-type="doi">10.5072/FK2/ABCDEF</inter_work_relation>
8+
</related_item>
9+
</program>
10+
</work>
11+
<work> <!-- With previous relation -->
12+
<program xmlns="http://www.crossref.org/relations.xsd" name="relations">
13+
<related_item>
14+
<intra_work_relation relationship-type="isPreprintOf" identifier-type="doi">https://doi.org/10.1234/LepidusPeriodico.1756</intra_work_relation>
15+
</related_item>
16+
<related_item>
17+
<description>Dataset deposited in Dataverse repository.</description>
18+
<inter_work_relation relationship-type="isSupplementedBy" identifier-type="doi">10.5072/FK2/ABCDEF</inter_work_relation>
19+
</related_item>
20+
</program>
21+
</work>
22+
</works>

0 commit comments

Comments
 (0)