Files
OSJ/plugins/generic/citationStyleLanguage/CitationStyleLanguagePlugin.php
CHIEFSOFT\ameye df3a033196 first commit
2024-06-08 17:09:23 -04:00

1003 lines
39 KiB
PHP

<?php
/**
* @file plugins/generic/citationStyleLanguage/CitationStyleLanguagePlugin.php
*
* Copyright (c) 2017-2020 Simon Fraser University
* Copyright (c) 2017-2020 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class CitationStyleLanguagePlugin
*
* @ingroup plugins_generic_citationStyleLanguage
*
* @brief Citation Style Language plugin class.
*/
namespace APP\plugins\generic\citationStyleLanguage;
require_once(__DIR__ . '/lib/vendor/autoload.php');
use APP\author\Author;
use APP\core\Application;
use APP\facades\Repo;
use APP\issue\Issue;
use APP\monograph\Chapter;
use APP\monograph\ChapterDAO;
use APP\plugins\generic\citationStyleLanguage\pages\CitationStyleLanguageHandler;
use APP\publication\Publication;
use APP\publicationFormat\PublicationFormat;
use APP\submission\Submission;
use APP\template\TemplateManager;
use Exception;
use PKP\core\JSONMessage;
use PKP\core\PKPApplication;
use PKP\core\PKPRequest;
use PKP\db\DAORegistry;
use PKP\facades\Locale;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\plugins\GenericPlugin;
use PKP\plugins\Hook;
use PKP\submission\SubmissionKeywordDAO;
use PKP\submission\SubmissionLanguageDAO;
use Seboettg\CiteProc\CiteProc;
use stdClass;
class CitationStyleLanguagePlugin extends GenericPlugin
{
/** @var array List of citation styles available */
public array $_citationStyles = [];
/** @var array List of citation download formats available */
public array $_citationDownloads = [];
/** @var string Name of the application */
public string $application;
protected bool $isBook = false;
protected bool $isChapter = false;
protected bool $isArticle = false;
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->application = Application::get()->getName();
}
/**
* @copydoc Plugin::getDisplayName()
*/
public function getDisplayName()
{
return __('plugins.generic.citationStyleLanguage.displayName');
}
/**
* @copydoc Plugin::getDescription()
*/
public function getDescription()
{
return __('plugins.generic.citationStyleLanguage.description');
}
/**
* @copydoc Plugin::register()
*
* @param null|mixed $mainContextId
*/
public function register($category, $path, $mainContextId = null)
{
$success = parent::register($category, $path, $mainContextId);
if (Application::isUnderMaintenance()) {
return $success;
}
if ($success && $this->getEnabled($mainContextId)) {
Hook::add('PreprintHandler::view', [$this, 'getTemplateData']);
Hook::add('CatalogBookHandler::book', [$this, 'getTemplateData']);
Hook::add('ArticleHandler::view', [$this, 'getTemplateData']);
Hook::add('Templates::Article::Details', [$this, 'addCitationMarkup']);
Hook::add('Templates::Catalog::Book::Details', [$this, 'addCitationMarkup']);
Hook::add('Templates::Catalog::Chapter::Details', [$this, 'addCitationMarkup']);
Hook::add('LoadHandler', [$this, 'setPageHandler']);
}
return $success;
}
/**
* Get list of citation styles available
*/
public function getCitationStyles(): array
{
if (!empty($this->_citationStyles)) {
return $this->_citationStyles;
}
$defaults = [
[
'id' => 'acm-sig-proceedings',
'title' => __('plugins.generic.citationStyleLanguage.style.acm-sig-proceedings'),
'isEnabled' => true,
],
[
'id' => 'acs-nano',
'title' => __('plugins.generic.citationStyleLanguage.style.acs-nano'),
'isEnabled' => true,
],
[
'id' => 'apa',
'title' => __('plugins.generic.citationStyleLanguage.style.apa'),
'isEnabled' => true,
'isPrimary' => true,
],
[
'id' => 'associacao-brasileira-de-normas-tecnicas',
'title' => __('plugins.generic.citationStyleLanguage.style.associacao-brasileira-de-normas-tecnicas'),
'isEnabled' => true,
],
[
'id' => 'chicago-author-date',
'title' => __('plugins.generic.citationStyleLanguage.style.chicago-author-date'),
'isEnabled' => true,
],
[
'id' => 'harvard-cite-them-right',
'title' => __('plugins.generic.citationStyleLanguage.style.harvard-cite-them-right'),
'isEnabled' => true,
],
[
'id' => 'ieee',
'title' => __('plugins.generic.citationStyleLanguage.style.ieee'),
'isEnabled' => true,
],
[
'id' => 'modern-language-association',
'title' => __('plugins.generic.citationStyleLanguage.style.modern-language-association'),
'isEnabled' => true,
],
[
'id' => 'turabian-fullnote-bibliography',
'title' => __('plugins.generic.citationStyleLanguage.style.turabian-fullnote-bibliography'),
'isEnabled' => true,
],
[
'id' => 'vancouver',
'title' => __('plugins.generic.citationStyleLanguage.style.vancouver'),
'isEnabled' => true,
],
[
'id' => 'ama',
'title' => __('plugins.generic.citationStyleLanguage.style.ama'),
'isEnabled' => true,
],
];
// If hooking in to add a custom .csl file, add a `useCsl` key to your
// style definition with the path to the file.
Hook::call('CitationStyleLanguage::citationStyleDefaults', [&$defaults, $this]);
$this->_citationStyles = $defaults;
return $this->_citationStyles;
}
/**
* Get the primary style name or default to the first available style
*/
public function getPrimaryStyleName(int $contextId): string
{
$primaryStyleName = $this->getSetting($contextId, 'primaryCitationStyle');
if ($primaryStyleName) {
return $primaryStyleName;
}
$styles = $this->getCitationStyles();
$primaryStyles = array_filter($styles, function ($style) {
return !empty($style['isPrimary']);
});
$primaryStyle = count($primaryStyles) ? array_shift($primaryStyles) : array_shift($styles);
return $primaryStyle['id'];
}
/**
* Get enabled citation styles
*/
public function getEnabledCitationStyles(int $contextId): array
{
$styles = $this->getCitationStyles();
$enabled = $this->getSetting($contextId, 'enabledCitationStyles');
if (!is_array($enabled)) {
return array_filter($styles, function ($style) {
return !empty($style['isEnabled']);
});
}
return array_filter($styles, function ($style) use ($enabled) {
return in_array($style['id'], $enabled);
});
}
/**
* Get list of citation download formats available
*/
public function getCitationDownloads(): array
{
if (!empty($this->_citationDownloads)) {
return $this->_citationDownloads;
}
$defaults = [
[
'id' => 'ris',
'title' => __('plugins.generic.citationStyleLanguage.download.ris'),
'isEnabled' => true,
'useTemplate' => $this->getTemplateResource('citation-styles/ris.tpl'),
'fileExtension' => 'ris',
'contentType' => 'application/x-Research-Info-Systems',
],
[
'id' => 'bibtex',
'title' => __('plugins.generic.citationStyleLanguage.download.bibtex'),
'isEnabled' => true,
'fileExtension' => 'bib',
'contentType' => 'application/x-bibtex',
],
];
// If hooking in to add a custom .csl file, add a `useCsl` key to your
// style definition with the path to the file.
Hook::call('CitationStyleLanguage::citationDownloadDefaults', [&$defaults, $this]);
$this->_citationDownloads = $defaults;
return $this->_citationDownloads;
}
/**
* Get enabled citation styles
*/
public function getEnabledCitationDownloads(int $contextId): array
{
$downloads = $this->getCitationDownloads();
$enabled = $this->getSetting($contextId, 'enabledCitationDownloads');
if (!is_array($enabled)) {
return array_filter($downloads, function ($style) {
return !empty($style['isEnabled']);
});
}
return array_filter($downloads, function ($style) use ($enabled) {
return in_array($style['id'], $enabled);
});
}
/**
* Pluck citation IDs from array of citations
*/
public function mapCitationIds(array $citations): array
{
return array_values(array_map(function ($citation) {
return $citation['id'];
}, $citations));
}
/**
* Get citation config for a citation ID (example: 'apa')
*/
public function getCitationStyleConfig(string $styleId): array
{
$styleConfigs = array_merge($this->getCitationStyles(), $this->getCitationDownloads());
$styleConfig = array_filter($styleConfigs, function ($styleConfig) use ($styleId) {
return $styleConfig['id'] === $styleId;
});
return array_shift($styleConfig);
}
protected function getPublicationTypeUrlPath(): string
{
return match ($this->application) {
'ojs2' => 'article',
'ops' => 'preprint',
'omp' => 'catalog',
default => ''
};
}
/**
* Retrieve citation information for the article details template. This
* method is hooked in before a template displays.
*
* @throws Exception
*/
public function getTemplateData(string $hookName, array $args): bool
{
$request = $args[0];
$templateMgr = TemplateManager::getManager($request);
$context = $request->getContext();
$contextId = $context->getId();
switch ($this->application) {
case 'ops':
$preprint = $args[1];
$publication = $args[2];
$citation = $this->getCitation($request, $preprint, $this->getPrimaryStyleName($contextId), null, $publication);
break;
case 'ojs2':
$issue = $args[1];
$submission = $args[2];
$publication = $args[3];
$chapter = null;
$citation = $this->getCitation($request, $submission, $this->getPrimaryStyleName($contextId), $issue, $publication);
break;
case 'omp':
/** @var Submission $submission */
$submission = & $args[1];
$publication = & $args[2];
$chapter = & $args[3];
$issue = null;
$citation = $this->getCitation($request, $submission, $this->getPrimaryStyleName($contextId), $issue, $publication);
break;
default:
throw new Exception('Unknown application!');
}
$citationArgs = [
'submissionId' => $submission->getId(),
'publicationId' => $publication->getId(),
];
if ($issue) {
$citationArgs['issueId'] = $issue->getId();
}
if ($chapter) {
$citationArgs['chapterId'] = $chapter->getId();
}
$citationArgsJson = $citationArgs;
$citationArgsJson['return'] = 'json';
$templateMgr->assign([
'citation' => $citation,
'citationArgs' => $citationArgs,
'citationArgsJson' => $citationArgsJson,
'citationStyles' => $this->getEnabledCitationStyles($contextId),
'citationDownloads' => $this->getEnabledCitationDownloads($contextId),
]);
$templateMgr->addStyleSheet(
'cslPluginStyles',
$request->getBaseUrl() . '/' . $this->getPluginPath() . '/css/citationStyleLanguagePlugin.css',
[
'priority' => TemplateManager::STYLE_SEQUENCE_LAST,
'contexts' => ['frontend'],
'inline' => false,
]
);
$templateMgr->addJavaScript(
'citationStyleLanguage',
$request->getBaseUrl() . '/' . $this->getPluginPath() . '/js/articleCitation.js'
);
return false;
}
public function addCitationMarkup(string $hookName, array $args): bool
{
$smarty = & $args[1];
$output = & $args[2];
$output .= $smarty->fetch($this->getTemplateResource('citationblock.tpl'));
return false;
}
/**
* Get a specified citation for a given article, book or chapter
*
* This citation format follows the csl-json schema and takes some direction
* from existing CSL mappings documented by Zotero and Mendeley.
*
* @see CSL-json schema https://github.com/citation-style-language/schema#csl-json-schema
* @see Zotero's mappings https://aurimasv.github.io/z2csl/typeMap.xml#map-journalArticle
* @see Mendeley's mappings http://support.mendeley.com/customer/portal/articles/364144-csl-type-mapping
*
* @param string $citationStyle Name of the citation style to use.
* @param Issue $issue Optional. Will fetch from db if not passed.
* @param Publication $publication Optional. A particular version
* @param Chapter $chapter Optional. OMP chapter pages only.
*
* @throws Exception
*/
public function getCitation(PKPRequest $request, Submission $submission, string $citationStyle = 'apa', ?Issue $issue = null, ?Publication $publication = null, ?Chapter $chapter = null): string
{
$publication ??= $submission->getCurrentPublication();
$context = $request->getContext();
if (!$chapter) {
$chapter = $this->application === 'omp' ? $this->getChapter($request, $publication) : null;
}
$this->setDocumentType($chapter);
/** @var SubmissionKeywordDAO $submissionKeywordDao */
$submissionKeywordDao = DAORegistry::getDAO('SubmissionKeywordDAO');
$keywords = $submissionKeywordDao->getKeywords($publication->getId(), [Locale::getSupportedLocales()]);
$citationData = new stdClass();
if ($this->isArticle) {
$citationData->type = ($this->application === 'ojs2' ? 'article-journal' : 'article');
$citationData->risType = 'JOUR';
$citationData->id = $submission->getId();
$citationData->title = $publication->getLocalizedFullTitle();
$citationData->{'container-title'} = $context->getLocalizedName();
$issueId = $publication->getData('issueId');
$issue ??= $issueId ? Repo::issue()->get($issueId) : null;
if ($issue) {
$citationData->volume = htmlspecialchars($issue->getData('volume'));
// Zotero prefers issue and Mendeley uses `number` to store revisions
$citationData->issue = htmlspecialchars($issue->getData('number'));
}
if ($sectionId = $publication->getData('sectionId')) {
$section = Repo::section()->get($sectionId);
if ($section && !$section->getHideTitle()) {
$citationData->section = htmlspecialchars($section->getTitle($context->getPrimaryLocale()));
}
}
$citationData->keywords = $keywords[Locale::getLocale()] ?? [];
if ($publication->getData('pages')) {
$citationData->page = htmlspecialchars($publication->getData('pages'));
}
$citationData->abstract = htmlspecialchars(strip_tags($publication->getLocalizedData('abstract')));
$citationData = $this->setArticleAuthors($citationData, $publication, $context);
$citationData->URL = $request->getDispatcher()->url($request, PKPApplication::ROUTE_PAGE, null, $this->getPublicationTypeUrlPath(), 'view', $submission->getBestId());
if ($publication->getDoi()) {
$citationData->DOI = $publication->getDoi();
}
} elseif ($this->isBook) {
$citationData->type = 'book';
$citationData->risType = 'BOOK';
$citationData->id = $submission->getId();
$citationData->title = $publication->getLocalizedFullTitle();
$citationData = $this->addSeriesInformation($citationData, $publication);
$citationData->publisher = htmlspecialchars($context->getLocalizedName());
$citationData->keywords = $keywords[Locale::getLocale()] ?? [];
if ($publication->getData('pages')) {
$citationData->page = htmlspecialchars($publication->getData('pages'));
}
$citationData->abstract = htmlspecialchars(strip_tags($publication->getLocalizedData('abstract')));
$citationData->serialNumber = $this->getSerialNumber($publication);
$citationData = $this->setBookAuthors($citationData, $publication, $context);
$citationData->URL = $request->getDispatcher()->url($request, PKPApplication::ROUTE_PAGE, null, $this->getPublicationTypeUrlPath(), 'book', $submission->getBestId());
if ($publication->getDoi()) {
$citationData->DOI = $publication->getDoi();
}
} elseif ($this->isChapter) {
$citationData->type = 'chapter';
$citationData->risType = 'CHAP';
$citationData->id = $chapter->getSourceChapterId();
$citationData->title = $chapter->getLocalizedFullTitle();
$citationData->{'container-title'} = $publication->getLocalizedFullTitle();
$citationData = $this->addSeriesInformation($citationData, $publication);
$citationData->publisher = htmlspecialchars($context->getLocalizedName());
if ($chapter->getPages()) {
$citationData->page = htmlspecialchars($chapter->getPages());
}
$citationData->abstract = htmlspecialchars(strip_tags($chapter->getLocalizedData('abstract')));
$citationData->serialNumber = $this->getSerialNumber($publication);
$citationData = $this->setBookChapterAuthors($citationData, $publication, $context, $chapter);
$citationData->URL = $request->getDispatcher()->url($request, PKPApplication::ROUTE_PAGE, null, $this->getPublicationTypeUrlPath(), 'book', [$submission->getBestId(), 'chapter', $chapter->getSourceChapterId()]);
if ($chapter->getDoi()) {
$citationData->DOI = $chapter->getDoi();
}
} else {
throw new Exception('Unknown submission content type!');
}
/** @var SubmissionLanguageDAO $submissionLanguageDao */
$submissionLanguageDao = DAORegistry::getDAO('SubmissionLanguageDAO');
$languages = $submissionLanguageDao->getLanguages($publication->getId(), [Locale::getLocale()]);
if (array_key_exists(Locale::getLocale(), $languages)) {
$citationData->languages = $languages[Locale::getLocale()];
}
$citationData->{'publisher-place'} = $this->getSetting($context->getId(), 'publisherLocation');
$abbreviation = $context->getData('abbreviation', $context->getPrimaryLocale()) ?? $context->getData('acronym', $context->getPrimaryLocale());
if ($abbreviation) {
$citationData->{'container-title-short'} = htmlspecialchars($abbreviation);
}
$citationData->accessed = new stdClass();
$citationData->accessed->raw = date('Y-m-d');
if ($publication->getData('datePublished')) {
$citationData->issued = new stdClass();
$citationData->issued->raw = htmlspecialchars($publication->getData('datePublished'));
$publishedPublications = $submission->getPublishedPublications();
if (count($publishedPublications) > 1) {
$originalPublication = array_reduce($publishedPublications, function ($a, $b) {
return $a && $a->getId() < $b->getId() ? $a : $b;
});
$originalDate = $originalPublication->getData('datePublished');
if ($originalDate && $originalDate !== $publication->getData('datePublished')) {
$citationData->{'original-date'} = new stdClass();
$citationData->{'original-date'}->raw = htmlspecialchars($originalPublication->getData('datePublished'));
}
}
} elseif ($this->isArticle && $issue?->getPublished()) {
$citationData->issued = new stdClass();
$citationData->issued->raw = htmlspecialchars($issue->getDatePublished());
}
Hook::call('CitationStyleLanguage::citation', [&$citationData, &$citationStyle, $submission, $issue, $context, $publication]);
$citation = '';
// Determine whether to use citeproc-php or a custom template to render
// the citation
$styleConfig = $this->getCitationStyleConfig($citationStyle);
if (!empty($styleConfig)) {
if (!empty($styleConfig['useTemplate'])) {
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'citationData' => $citationData,
'citationStyle' => $citationStyle,
'publication' => $publication,
]);
switch ($this->application) {
case 'ops':
case 'ojs2':
$templateMgr->assign([
'article' => $submission,
'issue' => $issue,
'journal' => $context,
]);
break;
case 'omp':
$templateMgr->assign([
'book' => $submission,
'press' => $context,
]);
break;
default: throw new Exception('Unknown application!');
}
$citation = $templateMgr->fetch($styleConfig['useTemplate']);
} else {
$style = $this->loadStyle($styleConfig);
if ($style) {
// Determine what locale to use. Try in order:
// - xx_YY
// - xx
// Fall back English if none found.
foreach ([
str_replace('_', '-', substr(Locale::getLocale(), 0, 5)),
substr(Locale::getLocale(), 0, 2),
'en-US',
] as $tryLocale) {
if (file_exists(dirname(__FILE__) . '/lib/vendor/citation-style-language/locales/locales-' . $tryLocale . '.xml')) {
break;
}
}
//Clickable URL and DOI including affixes
$additionalMarkup = [
'DOI' => [
'function' => function ($item, $renderedValue) {
return '<a href="https://doi.org/' . $item->DOI . '">' . $renderedValue . '</a>';
},
'affixes' => true
],
'URL' => [
'function' => function ($item, $renderedValue) {
return '<a href="' . $item->URL . '">' . $renderedValue . '</a>';
},
'affixes' => true
],
];
$citeProc = new CiteProc($style, $tryLocale, $additionalMarkup);
$citation = $citeProc->render([$citationData], 'bibliography');
}
}
}
return $citation;
}
/**
* Load a CSL style and return the contents as a string
*/
public function loadStyle(array $styleConfig): false|string
{
$path = empty($styleConfig['useCsl'])
? $this->getPluginPath() . '/citation-styles/' . $styleConfig['id'] . '.csl'
: $styleConfig['useCsl'];
return file_get_contents($path);
}
/**
* Download a citation format
*
* Downloadable citation formats can be used to import into third-party
* software.
*
* @param string $citationStyle Name of the citation style to use.
* @param Issue $issue Optional. Will fetch from db if not passed.
* @param $publication Publication Optional.
* @param $chapter Chapter Optional. OMP chapter pages only.
*/
public function downloadCitation(PKPRequest $request, Submission $submission, string $citationStyle = 'ris', ?Issue $issue = null, ?Publication $publication = null, ?Chapter $chapter = null)
{
if ($this->isArticle) {
$issueId = $submission->getCurrentPublication()->getData('issueId');
$issue ??= $issueId ? Repo::issue()->get($issueId) : null;
}
$styleConfig = $this->getCitationStyleConfig($citationStyle);
if (empty($styleConfig)) {
return false;
}
$citation = trim(strip_tags($this->getCitation($request, $submission, $citationStyle, $issue, $publication, $chapter)));
// TODO this is likely going to cause an error in a citation some day,
// but is necessary to get the .ris downloadable format working. The
// CSL language doesn't seem to offer a way to indicate a line break.
// See: https://github.com/citation-style-language/styles/issues/2831
$citation = str_replace('\n', "\n", $citation);
$encodedFilename = urlencode(substr(($publication ? $publication->getLocalizedTitle() : ''), 0, 60)) . '.' . $styleConfig['fileExtension'];
header("Content-Disposition: attachment; filename*=UTF-8''\"{$encodedFilename}\"");
header('Content-Type: ' . $styleConfig['contentType']);
echo $citation;
exit;
}
/**
* @see Plugin::getActions()
*/
public function getActions($request, $actionArgs)
{
$actions = parent::getActions($request, $actionArgs);
if (!$this->getEnabled()) {
return $actions;
}
$router = $request->getRouter();
$linkAction = new LinkAction(
'settings',
new AjaxModal(
$router->url(
$request,
null,
null,
'manage',
null,
[
'verb' => 'settings',
'plugin' => $this->getName(),
'category' => 'generic',
]
),
$this->getDisplayName()
),
__('manager.plugins.settings'),
null
);
array_unshift($actions, $linkAction);
return $actions;
}
/**
* @see Plugin::manage()
*/
public function manage($args, $request)
{
switch ($request->getUserVar('verb')) {
case 'settings':
$form = new CitationStyleLanguageSettingsForm($this);
if ($request->getUserVar('save')) {
$form->readInputData();
if ($form->validate()) {
$form->execute();
return new JSONMessage(true);
}
}
$form->initData();
return new JSONMessage(true, $form->fetch($request));
}
return parent::manage($args, $request);
}
/**
* Route requests for the citation styles to custom page handler
*/
public function setPageHandler(string $hookName, array $params): bool
{
$page = & $params[0];
$handler = & $params[3];
if ($this->getEnabled() && $page === 'citationstylelanguage') {
$handler = new CitationStyleLanguageHandler($this);
return true;
}
return false;
}
public function getEditorGroups(int $contextId): array
{
return $this->getSetting($contextId, 'groupEditor') ?? [];
}
public function getTranslatorGroups(int $contextId): array
{
return $this->getSetting($contextId, 'groupTranslator') ?? [];
}
public function getAuthorGroups(int $contextId): array
{
return $this->getSetting($contextId, 'groupAuthor') ?? [];
}
public function getChapterAuthorGroups(int $contextId): array
{
return $this->getSetting($contextId, 'groupChapterAuthor') ?? [];
}
public function getSerialNumber(Publication $publication): array
{
$serialNumber = [];
$publicationFormats = $publication->getData('publicationFormats');
/** @var PublicationFormat $publicationFormat */
foreach ($publicationFormats as $publicationFormat) {
if ($publicationFormat->getIsApproved()) {
$identificationCodes = $publicationFormat->getIdentificationCodes();
$identificationCodes = $identificationCodes->toArray();
foreach ($identificationCodes as $identificationCode) {
$serialNumber[] = htmlspecialchars($identificationCode->getValue());
}
}
}
return $serialNumber;
}
protected function addSeriesInformation(stdClass $citationData, Publication $publication): stdClass
{
$seriesId = $publication->getData('seriesId');
$series = $seriesId ? Repo::section()->get($seriesId) : null;
if (!$series) {
return $citationData;
}
$citationData->{'collection-title'} = htmlspecialchars(trim($series->getLocalizedFullTitle()));
$citationData->volume = htmlspecialchars($publication->getData('seriesPosition'));
$citationData->{'collection-editor'} = htmlspecialchars($series->getEditorsString());
$onlineISSN = $series->getOnlineISSN();
if (!empty($onlineISSN)) {
$citationData->serialNumber[] = htmlspecialchars($onlineISSN);
}
$printISSN = $series->getPrintISSN();
if (!empty($printISSN)) {
$citationData->serialNumber[] = htmlspecialchars($printISSN);
}
return $citationData;
}
protected function getChapter(PKPRequest $request, Publication $publication): ?Chapter
{
$args = $request->getRequestedArgs();
if (isset($args[1], $args[2]) && $args[1] === 'chapter') {
$key = 2;
} elseif (isset($args[1], $args[3], $args[4]) && $args[1] === 'version' && $args[3] === 'chapter') {
$key = 4;
} else {
return null;
}
$chapterId = (int) $args[$key];
if ($chapterId > 0) {
/** @var ChapterDAO */
$chapterDao = DAORegistry::getDAO('ChapterDAO');
return $chapterDao->getBySourceChapterAndPublication($chapterId, $publication->getId());
}
return null;
}
/**
* @throws Exception
*/
protected function setDocumentType($chapter): void
{
switch ($this->application) {
case 'ops':
case 'ojs2':
$this->isArticle = true;
break;
case 'omp':
if ($chapter) {
$this->isChapter = true;
} else {
$this->isBook = true;
}
break;
default: throw new Exception('Unknown application!');
}
}
protected function setArticleAuthors($citationData, $publication, $context): stdClass
{
$authors = $publication->getData('authors');
$authorsGroups = $this->getAuthorGroups($context->getId());
$translatorsGroups = $this->getTranslatorGroups($context->getId());
if (count($authors)) {
/** @var Author $author */
foreach ($authors as $author) {
$currentAuthor = new stdClass();
if (empty($author->getLocalizedFamilyName())) {
$currentAuthor->family = htmlspecialchars($author->getLocalizedGivenName());
} else {
$currentAuthor->family = htmlspecialchars($author->getLocalizedFamilyName());
$currentAuthor->given = htmlspecialchars($author->getLocalizedGivenName());
}
$userGroupId = $author->getUserGroupId();
switch (true) {
case in_array($userGroupId, $translatorsGroups):
if (!isset($citationData->translator)) {
$citationData->translator = [];
}
$citationData->translator[] = $currentAuthor;
break;
case in_array($userGroupId, $authorsGroups):
if (!isset($citationData->author)) {
$citationData->author = [];
}
$citationData->author[] = $currentAuthor;
break;
default:
if (!isset($citationData->author)) {
$citationData->author = [];
}
break;
}
}
}
return $citationData;
}
protected function setBookAuthors($citationData, $publication, $context): stdClass
{
$authors = $publication->getData('authors');
$authorsGroups = $this->getAuthorGroups($context->getId());
$editorsGroups = $this->getEditorGroups($context->getId());
$translatorsGroups = $this->getTranslatorGroups($context->getId());
if (count($authors)) {
/** @var Author $author */
foreach ($authors as $author) {
$currentAuthor = new stdClass();
if (empty($author->getLocalizedFamilyName())) {
$currentAuthor->family = htmlspecialchars($author->getLocalizedGivenName());
} else {
$currentAuthor->family = htmlspecialchars($author->getLocalizedFamilyName());
$currentAuthor->given = htmlspecialchars($author->getLocalizedGivenName());
}
$userGroupId = $author->getUserGroupId();
switch (true) {
case in_array($userGroupId, $editorsGroups):
if (!isset($citationData->editor)) {
$citationData->editor = [];
}
$citationData->editor[] = $currentAuthor;
break;
case in_array($userGroupId, $translatorsGroups):
if (!isset($citationData->translator)) {
$citationData->translator = [];
}
$citationData->translator[] = $currentAuthor;
break;
case in_array($userGroupId, $authorsGroups):
if (!isset($citationData->author)) {
$citationData->author = [];
}
$citationData->author[] = $currentAuthor;
break;
default:
if (!isset($citationData->author)) {
$citationData->author = [];
}
break;
}
}
}
return $citationData;
}
protected function setBookChapterAuthors($citationData, $publication, $context, $chapter): stdClass
{
$chapterAuthorGroups = $this->getChapterAuthorGroups($context->getId());
$chapterAuthors = $chapter->getAuthors();
/** @var Author $chapterAuthor */
foreach ($chapterAuthors as $chapterAuthor) {
$currentAuthor = new stdClass();
if (empty($chapterAuthor->getLocalizedFamilyName())) {
$currentAuthor->family = htmlspecialchars($chapterAuthor->getLocalizedGivenName());
} else {
$currentAuthor->family = htmlspecialchars($chapterAuthor->getLocalizedFamilyName());
$currentAuthor->given = htmlspecialchars($chapterAuthor->getLocalizedGivenName());
}
$userGroupId = $chapterAuthor->getUserGroupId();
if (in_array($userGroupId, $chapterAuthorGroups)) {
$citationData->author[] = $currentAuthor;
}
}
$bookAuthors = $publication->getData('authors');
$authorsGroups = $this->getAuthorGroups($context->getId());
$editorsGroups = $this->getEditorGroups($context->getId());
$translatorsGroups = $this->getTranslatorGroups($context->getId());
if (count($bookAuthors)) {
/** @var Author $bookAuthor */
foreach ($bookAuthors as $bookAuthor) {
$currentAuthor = new stdClass();
if (empty($bookAuthor->getLocalizedFamilyName())) {
$currentAuthor->family = htmlspecialchars($bookAuthor->getLocalizedGivenName());
} else {
$currentAuthor->family = htmlspecialchars($bookAuthor->getLocalizedFamilyName());
$currentAuthor->given = htmlspecialchars($bookAuthor->getLocalizedGivenName());
}
$userGroupId = $bookAuthor->getUserGroupId();
switch (true) {
case in_array($userGroupId, $editorsGroups):
if (!isset($citationData->editor)) {
$citationData->editor = [];
}
$citationData->editor[] = $currentAuthor;
break;
case in_array($userGroupId, $translatorsGroups):
if (!isset($citationData->translator)) {
$citationData->translator = [];
}
$citationData->translator[] = $currentAuthor;
break;
case in_array($userGroupId, $authorsGroups):
if (!isset($citationData->{'container-author'})) {
$citationData->{'container-author'} = [];
}
$citationData->{'container-author'}[] = $currentAuthor;
break;
default:
if (!isset($citationData->author)) {
$citationData->author = [];
}
break;
}
}
}
if (isset($citationData->{'container-author'})) {
$diffChapterAuthorsAuthors = array_udiff($citationData->{'container-author'}, $citationData->author, [$this, 'compareAuthors']);
if (count($diffChapterAuthorsAuthors) === 0) {
$citationData->{'container-author'} = [];
}
}
return $citationData;
}
protected function compareAuthors($a, $b): int
{
return 0 === strcmp($a->family, $b->family) && 0 === strcmp($a->given, $b->given) ? 0 : 1;
}
}