Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CrossrefPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -488,9 +488,9 @@ function ($attribute, $value, $fail) use ($context, $publication) {
];

$metadata = [
'publisherInstitution' => $context->getData('publisherInstitution'),
'onlineIssn' => $context->getData('onlineIssn'),
'printIssn' => $context->getData('printIssn'),
'publisherInstitution' => $publication->getPublisher($context),
'onlineIssn' => $publication->getOnlineIssn($context),
'printIssn' => $publication->getPrintIssn($context),
'doi' => $publication->getDoi(),
'issueId' => $issueId,
];
Expand Down
2 changes: 1 addition & 1 deletion filter/ArticleCrossrefXmlFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public function createSubmissionJournalNode(DOMDocument $doc, Submission $pubObj
$deployment = $this->getDeployment();

$journalNode = $doc->createElementNS($deployment->getNamespace(), 'journal');
$journalNode->appendChild($this->createJournalMetadataNode($doc));
$journalNode->appendChild($this->createJournalMetadataNode($doc, $publication));
$issueNode = $this->createSubmissionJournalIssueNode($doc, $publication);
if ($issueNode) {
$journalNode->appendChild($issueNode);
Expand Down
11 changes: 6 additions & 5 deletions filter/IssueCrossrefXmlFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use APP\core\Request;
use APP\issue\Issue;
use APP\plugins\generic\crossref\CrossrefExportDeployment;
use APP\publication\Publication;
use DOMDocument;
use DOMElement;
use PKP\core\Dispatcher;
Expand Down Expand Up @@ -129,22 +130,22 @@ public function createJournalNode(DOMDocument $doc, Issue $pubObject): DOMElemen
{
$deployment = $this->getDeployment();
$journalNode = $doc->createElementNS($deployment->getNamespace(), 'journal');
$journalNode->appendChild($this->createJournalMetadataNode($doc));
$journalNode->appendChild($this->createJournalMetadataNode($doc, $pubObject));
$journalNode->appendChild($this->createJournalIssueNode($doc, $pubObject));
return $journalNode;
}

/**
* Create and return the journal metadata node 'journal_metadata'.
*/
public function createJournalMetadataNode(DOMDocument $doc): DOMElement
public function createJournalMetadataNode(DOMDocument $doc, Issue|Publication $identitySource): DOMElement
{
$deployment = $this->getDeployment();
$context = $deployment->getContext();

$journalMetadataNode = $doc->createElementNS($deployment->getNamespace(), 'journal_metadata');
// Full title
$journalTitle = $context->getName($context->getPrimaryLocale());
$journalTitle = $identitySource->getPrimaryContextName($context);
// Fall back to the journal abbreviation if the full title is not set in the primary locale.
if ($journalTitle == '') {
$journalTitle = $context->getData('abbreviation', $context->getPrimaryLocale());
Expand All @@ -157,11 +158,11 @@ public function createJournalMetadataNode(DOMDocument $doc): DOMElement
}
$journalMetadataNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'abbrev_title', htmlspecialchars($journalAbbrev, ENT_COMPAT, 'UTF-8')));
// Both online and print ISSNs are permitted by Crossref — send whichever are available.
if ($ISSN = $context->getData('onlineIssn')) {
if ($ISSN = $identitySource->getOnlineIssn($context)) {
$journalMetadataNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'issn', $ISSN));
$node->setAttribute('media_type', 'electronic');
}
if ($ISSN = $context->getData('printIssn')) {
if ($ISSN = $identitySource->getPrintIssn($context)) {
$journalMetadataNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'issn', $ISSN));
$node->setAttribute('media_type', 'print');
}
Expand Down
96 changes: 96 additions & 0 deletions tests/JournalMetadataNodeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

/**
* @file plugins/generic/crossref/tests/JournalMetadataNodeTest.php
*
* Copyright (c) 2026 Simon Fraser University
* Copyright (c) 2026 John Willinsky
* Distributed under The MIT License. For full terms see the file LICENSE.
*
* @class JournalMetadataNodeTest
*
* @brief Tests that createJournalMetadataNode() uses stamped identity values
* from the publication rather than the journal's current values after a rename or ISSN change.
*/

namespace APP\plugins\generic\crossref\tests;

use APP\journal\Journal;
use APP\plugins\generic\crossref\CrossrefExportDeployment;
use APP\plugins\generic\crossref\filter\IssueCrossrefXmlFilter;
use APP\publication\DAO;
use APP\publication\Publication;
use DOMDocument;
use Mockery;
use PHPUnit\Framework\Attributes\CoversClass;
use PKP\core\Registry;
use PKP\services\PKPSchemaService;
use PKP\site\Site;
use PKP\tests\PKPTestCase;

#[CoversClass(IssueCrossrefXmlFilter::class)]
class JournalMetadataNodeTest extends PKPTestCase
{
private Publication $publication;
private IssueCrossrefXmlFilter $filter;

protected function getMockedRegistryKeys(): array
{
return ['site'];
}

protected function setUp(): void
{
parent::setUp();

// getLocalePrecedence() accesses the request and site — set up minimal mocks.
$mockSite = Mockery::mock(Site::class);
$mockSite->shouldReceive('getPrimaryLocale')->andReturn('en');
Registry::set('site', $mockSite);
$this->mockRequest();

$this->publication = (new DAO(new PKPSchemaService()))->newDataObject();

$this->filter = $this->getMockBuilder(IssueCrossrefXmlFilter::class)
->disableOriginalConstructor()
->onlyMethods([])
->getMock();
}

private function setupDeployment(Journal $journal): void
{
$deployment = Mockery::mock(CrossrefExportDeployment::class);
$deployment->shouldReceive('getContext')->andReturn($journal);
$deployment->shouldReceive('getNamespace')->andReturn(CrossrefExportDeployment::CROSSREF_XMLNS);
$this->filter->setDeployment($deployment);
}

public function testJournalMetadataUsesStampedIdentityAfterJournalChange(): void
{
$journal = new Journal();
$journal->setName('Old Journal Name', 'en');
$journal->setPrimaryLocale('en');
$journal->setData('onlineIssn', 'old-online-issn');
$journal->setData('printIssn', 'old-print-issn');
$journal->setData('publisherInstitution', 'Old Publisher');
$journal->setData('abbreviation', 'J.Old', 'en');

$this->publication->stampContextIdentity($journal);

// Journal is later renamed and its ISSNs changed — the stamp must remain authoritative.
$journal->setName('New Journal Name', 'en');
$journal->setData('onlineIssn', 'new-online-issn');
$journal->setData('printIssn', 'new-print-issn');

$this->setupDeployment($journal);
$xml = $this->filter->createJournalMetadataNode(new DOMDocument(), $this->publication);
$xmlString = $xml->ownerDocument->saveXML($xml);

$this->assertStringContainsString('<full_title>Old Journal Name</full_title>', $xmlString);
$this->assertStringContainsString('old-online-issn', $xmlString);
$this->assertStringContainsString('old-print-issn', $xmlString);
$this->assertStringNotContainsString('New Journal Name', $xmlString);
$this->assertStringNotContainsString('new-online-issn', $xmlString);
$this->assertStringNotContainsString('new-print-issn', $xmlString);
}
}