<?php
/**
* @file classes/publication/PKPPublication.php
*
* Copyright (c) 2016-2021 Simon Fraser University
* Copyright (c) 2003-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PKPPublication
*
* @ingroup publication
*
* @see DAO
*
* @brief Base class for Publication.
*/
namespace PKP\publication;
use APP\author\Author;
use APP\facades\Repo;
use PKP\core\Core;
use PKP\core\PKPString;
use PKP\facades\Locale;
use PKP\userGroup\UserGroup;
class PKPPublication extends \PKP\core\DataObject
{
/**
* Get the default/fall back locale the values should exist for
*/
public function getDefaultLocale(): ?string
{
return $this->getData('locale');
}
/**
* Combine the localized title, prefix and subtitle
*
* @param string $preferredLocale Override the publication's default locale and return the title in a specified locale.
* @param string $format Define the return data format as text or html
*
* @return string
*/
public function getLocalizedFullTitle($preferredLocale = null, string $format = 'text')
{
$fullTitle = $this->getLocalizedTitle($preferredLocale, $format);
$subtitle = $this->getLocalizedSubTitle($preferredLocale, $format);
if ($subtitle) {
return PKPString::concatTitleFields([$fullTitle, $subtitle]);
}
return $fullTitle;
}
/**
* Return the combined prefix, title and subtitle for all locales
*
* @param string $format Define the return data format as text or html
*
* @return array
*/
public function getFullTitles(string $format = 'text')
{
$allTitles = (array) $this->getData('title');
$return = [];
foreach ($allTitles as $locale => $title) {
if (!$title) {
continue;
}
$return[$locale] = $this->getLocalizedFullTitle($locale, $format);
}
return $return;
}
/**
* Combine the localized title and prefix
*
* @param string $preferredLocale Override the publication's default locale and return the title in a specified locale.
* @param string $format Define the return data format as text or html
*
* @return string
*/
public function getLocalizedTitle($preferredLocale = null, string $format = 'text')
{
$usedLocale = null;
$title = $this->getLocalizedData('title', $preferredLocale, $usedLocale);
$prefix = $this->getData('prefix', $usedLocale);
switch (strtolower($format)) {
case 'html':
// Title is already in HTML, prefix is in text. Convert prefix.
if ($prefix) {
$prefix = htmlspecialchars($prefix);
}
break;
case 'text':
// Title is in HTML, prefix is already in text. Convert title.
$title = strip_tags($title);
break;
default: throw new \Exception('Invalid format!');
}
if ($prefix) {
$title = $prefix . ' ' . $title;
}
return $title;
}
/**
* Get the localized sub title
*
* @param string $preferredLocale Override the publication's default locale and return the title in a specified locale.
* @param string $format Define the return data format as text or html
*
* @return string
*/
public function getLocalizedSubTitle($preferredLocale = null, string $format = 'text')
{
$subTitle = $this->getLocalizedData('subtitle', $preferredLocale);
if ($subTitle) {
return strtolower($format) === 'text' ? strip_tags($subTitle) : $subTitle;
}
return '';
}
/**
* Return the combined title and prefix for all locales
*
* @param string $format Define the return data format as text or html
*
* @return array
*/
public function getTitles(string $format = 'text')
{
$allTitles = $this->getData('title');
$return = [];
foreach ($allTitles as $locale => $title) {
if (!$title) {
continue;
}
$return[$locale] = $this->getLocalizedTitle($locale, $format);
}
return $return;
}
/**
* Return all the sub titles
*
* @param string $format Define the return data format as text or html
*
* @return array
*/
public function getSubTitles(string $format = 'text')
{
$allSubTitles = $this->getData('subtitle');
$return = [];
foreach ($allSubTitles ?? [] as $locale => $subTitle) {
if (!$subTitle) {
continue;
}
$return[$locale] = $this->getLocalizedSubTitle($locale, $format);
}
return $return;
}
/**
* Combine author names and roles into a string
*
* Eg - Daniel Barnes, Carlo Corino (Author); Alan Mwandenga (Translator)
*
* @param \Traversable<UserGroup> $userGroups List of UserGroup objects
* @param bool $includeInBrowseOnly true if only the includeInBrowse Authors will be contained
*
* @return string
*/
public function getAuthorString(\Traversable $userGroups, $includeInBrowseOnly = false)
{
$authors = $this->getData('authors');
if (empty($authors)) {
return '';
}
if ($includeInBrowseOnly) {
$authors = $authors->filter(function ($author, $key) {
return $author->getData('includeInBrowse');
});
}
$str = '';
$lastUserGroupId = null;
foreach ($authors as $author) {
if (!empty($str)) {
if ($lastUserGroupId != $author->getData('userGroupId')) {
foreach ($userGroups as $userGroup) {
if ($lastUserGroupId === $userGroup->getId()) {
if ($userGroup->getData('showTitle')) {
$str .= ' (' . $userGroup->getLocalizedData('name') . ')';
}
break;
}
}
$str .= __('common.semicolonListSeparator');
} else {
$str .= __('common.commaListSeparator');
}
}
$str .= $author->getFullName();
$lastUserGroupId = $author->getUserGroupId();
}
// If there needs to be a trailing user group title, add it
if (isset($author)) {
foreach ($userGroups as $userGroup) {
if ($author->getData('userGroupId') === $userGroup->getId()) {
if ($userGroup->getData('showTitle')) {
$str .= ' (' . $userGroup->getLocalizedData('name') . ')';
}
break;
}
}
}
return $str;
}
/**
* Combine the author names into a shortened string
*
* Eg - Barnes, et al.
*
* @param string|null $defaultLocale
*
* @return string
*/
public function getShortAuthorString($defaultLocale = null)
{
$authors = $this->getData('authors');
if (!$authors->count()) {
return '';
}
$firstAuthor = $authors->first();
$str = $firstAuthor->getLocalizedData('familyName', $defaultLocale);
if (!$str) {
$str = $firstAuthor->getLocalizedData('givenName', $defaultLocale);
}
if ($authors->count() > 1) {
return __('submission.shortAuthor', ['author' => $str], $defaultLocale);
}
return $str;
}
/**
* Get the primary contact
*
* @return Author|null
*/
public function getPrimaryAuthor()
{
if (empty($this->getData('authors'))) {
return null;
}
foreach ($this->getData('authors') as $author) {
if ($author->getId() === $this->getData('primaryContactId')) {
return $author;
}
}
}
/**
* Stamp the date of the last modification to the current time.
*/
public function stampModified()
{
return $this->setData('lastModified', Core::getCurrentDate());
}
/**
* Get the starting page of this publication
*
* Note the return type of string - this is not to be used for
* page counting.
*
* @return string
*/
public function getStartingPage()
{
$ranges = $this->getPageArray();
$firstRange = array_shift($ranges);
if (is_array($firstRange)) {
return array_shift($firstRange);
}
return '';
}
/**
* Get ending page of a this publication
*
* Note the return type of string - this is not to be used for
* page counting.
*
* @return string
*/
public function getEndingPage()
{
$ranges = $this->getPageArray();
$lastRange = array_pop($ranges);
$lastPage = is_array($lastRange) ? array_pop($lastRange) : '';
return $lastPage ?? '';
}
/**
* Get pages converted to a nested array of page ranges
*
* For example, pages of "pp. ii-ix, 9,15-18,a2,b2-b6" will return:
*
* [
* ['ii', 'ix'],
* ['9'],
* ['15', '18'],
* ['a2'],
* ['b2', 'b6'],
* ]
*
* @return array
*/
public function getPageArray()
{
$pages = $this->getData('pages') ?? '';
// Strip any leading word
if (preg_match('/^[[:alpha:]]+\W/', $pages)) {
// but don't strip a leading roman numeral
if (!preg_match('/^[MDCLXVUI]+\W/i', $pages)) {
// strip the word or abbreviation, including the period or colon
$pages = preg_replace('/^[[:alpha:]]+[:.]?/', '', $pages);
}
}
// strip leading and trailing space
$pages = trim($pages);
// shortcut the explode/foreach if the remainder is an empty value
if ($pages === '') {
return [];
}
// commas indicate distinct ranges
$ranges = explode(',', $pages);
$pageArray = [];
foreach ($ranges as $range) {
// hyphens (or double-hyphens) indicate range spans
$pageArray[] = array_map('trim', explode('-', str_replace(['--', '–'], '-', $range), 2));
}
return $pageArray;
}
/**
* Is the license for copyright on this publication a Creative Commons license?
*
* @return bool
*/
public function isCCLicense()
{
return preg_match('/creativecommons\.org/i', $this->getData('licenseUrl'));
}
/**
* Helper method to fetch current DOI
*
*/
public function getDoi(): ?string
{
$doiObject = $this->getData('doiObject');
if (empty($doiObject)) {
return null;
} else {
return $doiObject->getData('doi');
}
}
/**
* Get stored public ID of the publication
*
* This helper function is required by PKPPubIdPlugins.
* NB: To maintain backwards compatability, getDoi() is called from here
*
* @see Submission::getStoredPubId()
*/
public function getStoredPubId($pubIdType)
{
if ($pubIdType === 'doi') {
return $this->getDoi();
} else {
return $this->getData('pub-id::' . $pubIdType);
}
}
/**
* Set stored public issue id.
*
* @param string $pubIdType One of the NLM pub-id-type values or
* 'other::something' if not part of the official NLM list
* (see <http://dtd.nlm.nih.gov/publishing/tag-library/n-4zh0.html>).
* @param string $pubId
*/
public function setStoredPubId($pubIdType, $pubId)
{
if ($pubIdType == 'doi') {
if ($doiObject = $this->getData('doiObject')) {
Repo::doi()->edit($doiObject, ['doi' => $pubId]);
} else {
$newDoiObject = Repo::doi()->newDataObject(
[
'doi' => $pubId,
'contextId' => Repo::submission()->get($this->getData('submissionId'))->getData('contextId')
]
);
$doiId = Repo::doi()->add($newDoiObject);
$this->setData('doiId', $doiId);
}
} else {
$this->setData('pub-id::' . $pubIdType, $pubId);
}
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\publication\PKPPublication', '\PKPPublication');
}
|