first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-06-08 17:09:23 -04:00
commit df3a033196
17887 changed files with 8637778 additions and 0 deletions
+141
View File
@@ -0,0 +1,141 @@
<?php
/**
* @file classes/publication/Collector.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class Collector
*
* @brief A helper class to configure a Query Builder to get a collection of announcements
*/
namespace PKP\publication;
use APP\publication\Publication;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\LazyCollection;
use PKP\core\interfaces\CollectorInterface;
use PKP\plugins\Hook;
/**
* @template T of Publication
*/
class Collector implements CollectorInterface
{
public \APP\publication\DAO $dao;
public ?array $contextIds;
public ?array $submissionIds;
public ?array $doiIds = null;
public ?int $count;
public ?int $offset;
public function __construct(DAO $dao)
{
$this->dao = $dao;
}
public function getCount(): int
{
return $this->dao->getCount($this);
}
/**
* @return Collection<int,int>
*/
public function getIds(): Collection
{
return $this->dao->getIds($this);
}
/**
* @copydoc DAO::getMany()
* @return LazyCollection<int,T>
*/
public function getMany(): LazyCollection
{
return $this->dao->getMany($this);
}
/**
* Filter by contexts
*/
public function filterByContextIds(?array $contextIds): self
{
$this->contextIds = $contextIds;
return $this;
}
/**
* Filter by submissions
*/
public function filterBySubmissionIds(?array $submissionIds): self
{
$this->submissionIds = $submissionIds;
return $this;
}
public function filterByDoiIds(?array $doiIds): self
{
$this->doiIds = $doiIds;
return $this;
}
/**
* Limit the number of objects retrieved
*/
public function limit(?int $count): self
{
$this->count = $count;
return $this;
}
/**
* Offset the number of objects retrieved, for example to
* retrieve the second page of contents
*/
public function offset(?int $offset): self
{
$this->offset = $offset;
return $this;
}
/**
* @copydoc CollectorInterface::getQueryBuilder()
*/
public function getQueryBuilder(): Builder
{
$qb = DB::table('publications as p')
->select(['p.*']);
if (isset($this->contextIds)) {
$qb->join('submissions as s', 'p.submission_id', '=', 's.submission_id');
$qb->whereIn('s.context_id', $this->contextIds);
}
if (isset($this->submissionIds)) {
$qb->whereIn('p.submission_id', $this->submissionIds);
}
$qb->when($this->doiIds !== null, function (Builder $qb) {
$qb->whereIn('p.doi_id', $this->doiIds);
});
if (isset($this->count)) {
$qb->limit($this->count);
}
if (isset($this->offset)) {
$qb->offset($this->offset);
}
$qb->orderBy('p.version', 'asc');
// Add app-specific query statements
Hook::call('Publication::Collector', [&$qb, $this]);
return $qb;
}
}
+548
View File
@@ -0,0 +1,548 @@
<?php
/**
* @file classes/publication/DAO.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class DAO
*
* @brief Read and write publications to the database.
*/
namespace PKP\publication;
use APP\facades\Repo;
use APP\publication\Publication;
use Illuminate\Support\Collection;
use Illuminate\Support\Enumerable;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\LazyCollection;
use PKP\citation\CitationDAO;
use PKP\core\EntityDAO;
use PKP\core\traits\EntityWithParent;
use PKP\services\PKPSchemaService;
use PKP\submission\SubmissionAgencyDAO;
use PKP\submission\SubmissionDisciplineDAO;
use PKP\submission\SubmissionKeywordDAO;
use PKP\submission\SubmissionLanguageDAO;
use PKP\submission\SubmissionSubjectDAO;
/**
* @template T of Publication
* @extends EntityDAO<T>
*/
class DAO extends EntityDAO
{
use EntityWithParent;
/** @copydoc EntityDAO::$schema */
public $schema = PKPSchemaService::SCHEMA_PUBLICATION;
/** @copydoc EntityDAO::$table */
public $table = 'publications';
/** @copydoc EntityDAO::$settingsTable */
public $settingsTable = 'publication_settings';
/** @copydoc EntityDAO::$primaryKeyColumn */
public $primaryKeyColumn = 'publication_id';
/** @var SubmissionKeywordDAO */
public $submissionKeywordDao;
/** @var SubmissionSubjectDAO */
public $submissionSubjectDao;
/** @var SubmissionDisciplineDAO */
public $submissionDisciplineDao;
/** @var SubmissionLanguageDAO */
public $submissionLanguageDao;
/** @var SubmissionAgencyDAO */
public $submissionAgencyDao;
/** @var CitationDAO */
public $citationDao;
/**
* Constructor
*/
public function __construct(
SubmissionKeywordDAO $submissionKeywordDao,
SubmissionSubjectDAO $submissionSubjectDao,
SubmissionDisciplineDAO $submissionDisciplineDao,
SubmissionLanguageDAO $submissionLanguageDao,
SubmissionAgencyDAO $submissionAgencyDao,
CitationDAO $citationDao,
PKPSchemaService $schemaService
) {
parent::__construct($schemaService);
$this->submissionKeywordDao = $submissionKeywordDao;
$this->submissionSubjectDao = $submissionSubjectDao;
$this->submissionDisciplineDao = $submissionDisciplineDao;
$this->submissionLanguageDao = $submissionLanguageDao;
$this->submissionAgencyDao = $submissionAgencyDao;
$this->citationDao = $citationDao;
}
/**
* Get the parent object ID column name
*/
public function getParentColumn(): string
{
return 'submission_id';
}
/**
* Instantiate a new DataObject
*/
public function newDataObject(): Publication
{
return app(Publication::class);
}
/**
* Get the total count of rows matching the configured query
*/
public function getCount(Collector $query): int
{
return $query
->getQueryBuilder()
->count();
}
/**
* Get a list of ids matching the configured query
*
* @return Collection<int,int>
*/
public function getIds(Collector $query): Collection
{
return $query
->getQueryBuilder()
->select('p.' . $this->primaryKeyColumn)
->pluck('p.' . $this->primaryKeyColumn);
}
/**
* Get a collection of publications matching the configured query
* @return LazyCollection<int,T>
*/
public function getMany(Collector $query): LazyCollection
{
$rows = $query
->getQueryBuilder()
->get();
return LazyCollection::make(function () use ($rows) {
foreach ($rows as $row) {
yield $row->publication_id => $this->fromRow($row);
}
});
}
/**
* Get the publication dates of the first and last publications
* matching the passed query
*
* @return object self::$min_date_published, self::$max_date_published
*/
public function getDateBoundaries(Collector $query): object
{
return $query
->getQueryBuilder()
->reorder()
->select([
DB::raw('MIN(p.date_published) AS min_date_published, MAX(p.date_published) AS max_date_published')
])
->first();
}
/**
* Is the urlPath a duplicate?
*
* Checks if the urlPath is used in any other submission than the one
* passed
*
* A urlPath may be duplicated across more than one publication of the
* same submission. But two publications in two different submissions
* can not share the same urlPath.
*
* This is only applied within a single context.
*/
public function isDuplicateUrlPath(string $urlPath, int $submissionId, int $contextId): bool
{
if (!strlen($urlPath)) {
return false;
}
return (bool) DB::table('publications as p')
->leftJoin('submissions as s', 's.submission_id', '=', 'p.submission_id')
->where('url_path', '=', $urlPath)
->where('p.submission_id', '!=', $submissionId)
->where('s.context_id', '=', $contextId)
->count();
}
/**
* @copydoc EntityDAO::fromRow()
*/
public function fromRow(object $row): Publication
{
$publication = parent::fromRow($row);
$this->setDoiObject($publication);
// Set the primary locale from the submission
$locale = DB::table('submissions as s')
->where('s.submission_id', '=', $publication->getData('submissionId'))
->value('locale');
$publication->setData('locale', $locale);
$this->setAuthors($publication);
$this->setCategories($publication);
$this->setControlledVocab($publication);
return $publication;
}
/**
* @copydoc EntityDAO::insert()
*/
public function insert(Publication $publication): int
{
$vocabs = $this->extractControlledVocab($publication);
$id = parent::_insert($publication);
$this->saveControlledVocab($vocabs, $id);
$this->saveCategories($publication);
// Parse the citations
if ($publication->getData('citationsRaw')) {
$this->saveCitations($publication);
}
return $id;
}
/**
* @copydoc EntityDAO::update()
*/
public function update(Publication $publication, Publication $oldPublication = null)
{
$vocabs = $this->extractControlledVocab($publication);
parent::_update($publication);
$this->saveControlledVocab($vocabs, $publication->getId());
$this->saveCategories($publication);
if ($oldPublication && $oldPublication->getData('citationsRaw') != $publication->getData('citationsRaw')) {
$this->saveCitations($publication);
}
}
/**
* @copydoc EntityDAO::delete()
*/
public function delete(Publication $publication)
{
parent::_delete($publication);
}
/**
* @copydoc EntityDAO::deleteById()
*/
public function deleteById(int $publicationId)
{
parent::deleteById($publicationId);
$this->deleteAuthors($publicationId);
$this->deleteCategories($publicationId);
$this->deleteControlledVocab($publicationId);
$this->deleteCitations($publicationId);
}
/**
* Get publication ids that have a matching setting
*/
public function getIdsBySetting(string $settingName, $settingValue, int $contextId): Enumerable
{
$q = DB::table($this->table . ' as p')
->join($this->settingsTable . ' as ps', 'p.publication_id', '=', 'ps.publication_id')
->join('submissions as s', 'p.submission_id', '=', 's.submission_id')
->where('ps.setting_name', '=', $settingName)
->where('ps.setting_value', '=', $settingValue)
->where('s.context_id', '=', (int) $contextId);
return $q->select('p.publication_id')
->pluck('p.publication_id');
}
/**
* @copydoc PKPPubIdPluginDAO::pubIdExists()
*/
public function pubIdExists($pubIdType, $pubId, $excludePubObjectId, int $contextId)
{
$result = $this->deprecatedDao->retrieve(
'SELECT COUNT(*) AS row_count
FROM publication_settings ps
LEFT JOIN publications p ON p.publication_id = ps.publication_id
LEFT JOIN submissions s ON p.submission_id = s.submission_id
WHERE ps.setting_name = ? and ps.setting_value = ? and s.submission_id <> ? AND s.context_id = ?',
[
'pub-id::' . $pubIdType,
$pubId,
// The excludePubObjectId refers to the submission id
// because multiple versions of the same submission
// are allowed to share a DOI.
(int) $excludePubObjectId,
(int) $contextId
]
);
$row = $result->current();
return $row ? (bool) $row->row_count : false;
}
/**
* @copydoc PKPPubIdPluginDAO::changePubId()
*/
public function changePubId($pubObjectId, $pubIdType, $pubId)
{
DB::table($this->settingsTable)
->update([
'publication_id' => (int) $pubObjectId,
'locale' => '',
'setting_name' => 'pub-id::' . $pubIdType,
'setting_value' => (string) $pubId
]);
}
/**
* @copydoc PKPPubIdPluginDAO::deletePubId()
*/
public function deletePubId($pubObjectId, $pubIdType)
{
DB::table($this->settingsTable)
->where('publication_id', (int) $pubObjectId)
->where('setting_name', '=', 'pub-id::' . $pubIdType)
->delete();
}
/**
* @copydoc PKPPubIdPluginDAO::deleteAllPubIds()
*/
public function deleteAllPubIds($contextId, $pubIdType)
{
switch (DB::getDriverName()) {
case 'mysql':
$this->deprecatedDao->update(
'DELETE ps FROM publication_settings ps
LEFT JOIN publications p ON p.publication_id = ps.publication_id
LEFT JOIN submissions s ON s.submission_id = p.submission_id
WHERE ps.setting_name = ?
AND s.context_id = ?',
[
'pub-id::' . $pubIdType,
$contextId,
]
);
break;
case 'pgsql':
$this->deprecatedDao->update(
'DELETE FROM publication_settings
USING publication_settings ps
LEFT JOIN publications p ON p.publication_id = ps.publication_id
LEFT JOIN submissions s ON s.submission_id = p.submission_id
WHERE ps.setting_name = ?
AND s.context_id = ?
AND ps.publication_id = publication_settings.publication_id
AND ps.locale = publication_settings.locale
AND ps.setting_name = publication_settings.setting_name',
[
'pub-id::' . $pubIdType,
$contextId,
]
);
break;
default: fatalError('Unknown database type!');
}
$this->deprecatedDao->flushCache();
}
/**
* Set a publication's author properties
*/
protected function setAuthors(Publication $publication)
{
$publication->setData(
'authors',
Repo::author()
->getCollector()
->filterByPublicationIds([$publication->getId()])
->orderBy(\PKP\author\Collector::ORDERBY_SEQUENCE)
->getMany()
->remember()
);
}
/**
* Delete a publication's authors
*/
protected function deleteAuthors(int $publicationId)
{
$authors = Repo::author()
->getCollector()
->filterByPublicationIds([$publicationId])
->getMany();
foreach ($authors as $author) {
Repo::author()->delete($author);
}
}
/**
* Set a publication's controlled vocabulary properties
*/
protected function setControlledVocab(Publication $publication)
{
$publication->setData('keywords', $this->submissionKeywordDao->getKeywords($publication->getId()));
$publication->setData('subjects', $this->submissionSubjectDao->getSubjects($publication->getId()));
$publication->setData('disciplines', $this->submissionDisciplineDao->getDisciplines($publication->getId()));
$publication->setData('languages', $this->submissionLanguageDao->getLanguages($publication->getId()));
$publication->setData('supportingAgencies', $this->submissionAgencyDao->getAgencies($publication->getId()));
}
/**
* Remove controlled vocabulary from a publication's data
*
* Controlled vocabulary includes keywords, subjects, and similar
* metadata that shouldn't be saved in the publications table.
*
* @see self::saveControlledVocab()
*
* @return array Key/value of controlled vocabulary properties
*/
protected function extractControlledVocab(Publication $publication): array
{
$controlledVocabKeyedArray = array_flip([
'disciplines',
'keywords',
'languages',
'subjects',
'supportingAgencies',
]);
$values = array_intersect_key($publication->_data, $controlledVocabKeyedArray);
$publication->setAllData(array_diff_key($publication->_data, $controlledVocabKeyedArray));
return $values;
}
/**
* Save controlled vocabulary properties
*
* @see self::extractControlledVocab()
*/
protected function saveControlledVocab(array $values, int $publicationId)
{
// Update controlled vocabularly for which we have props
foreach ($values as $prop => $value) {
switch ($prop) {
case 'keywords':
$this->submissionKeywordDao->insertKeywords($value, $publicationId);
break;
case 'subjects':
$this->submissionSubjectDao->insertSubjects($value, $publicationId);
break;
case 'disciplines':
$this->submissionDisciplineDao->insertDisciplines($value, $publicationId);
break;
case 'languages':
$this->submissionLanguageDao->insertLanguages($value, $publicationId);
break;
case 'supportingAgencies':
$this->submissionAgencyDao->insertAgencies($value, $publicationId);
break;
}
}
}
/**
* Delete controlled vocab entries for a publication
*/
protected function deleteControlledVocab(int $publicationId)
{
$this->submissionKeywordDao->insertKeywords([], $publicationId);
$this->submissionSubjectDao->insertSubjects([], $publicationId);
$this->submissionDisciplineDao->insertDisciplines([], $publicationId);
$this->submissionLanguageDao->insertLanguages([], $publicationId);
$this->submissionAgencyDao->insertAgencies([], $publicationId);
}
/**
* Set a publication's category property
*/
protected function setCategories(Publication $publication)
{
$publication->setData(
'categoryIds',
Repo::category()->getCollector()
->filterByPublicationIds([$publication->getId()])
->getIds()
->toArray()
);
}
/**
* Save the assigned categories
*/
protected function saveCategories(Publication $publication)
{
Repo::category()->dao->deletePublicationAssignments($publication->getId());
if (!empty($publication->getData('categoryIds'))) {
foreach ($publication->getData('categoryIds') as $categoryId) {
Repo::category()->dao->insertPublicationAssignment($categoryId, $publication->getId());
}
}
}
/**
* Delete the category assignments
*/
protected function deleteCategories(int $publicationId)
{
Repo::category()->dao->deletePublicationAssignments($publicationId);
}
/**
* Save the citations
*/
protected function saveCitations(Publication $publication)
{
$this->citationDao->importCitations($publication->getId(), $publication->getData('citationsRaw'));
}
/**
* Delete the citations
*/
protected function deleteCitations(int $publicationId)
{
$this->citationDao->deleteByPublicationId($publicationId);
}
/**
* Set the DOI object
*
*/
protected function setDoiObject(Publication $publication)
{
if (!empty($publication->getData('doiId'))) {
$publication->setData('doiObject', Repo::doi()->get($publication->getData('doiId')));
}
}
}
@@ -0,0 +1,438 @@
<?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');
}
+735
View File
@@ -0,0 +1,735 @@
<?php
/**
* @file classes/publication/Repository.php
*
* Copyright (c) 2014-2020 Simon Fraser University
* Copyright (c) 2000-2020 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class Repository
*
* @brief A repository to find and manage publications.
*/
namespace PKP\publication;
use APP\core\Application;
use APP\core\Request;
use APP\core\Services;
use APP\facades\Repo;
use APP\file\PublicFileManager;
use APP\publication\DAO;
use APP\publication\Publication;
use APP\submission\Submission;
use Illuminate\Support\Enumerable;
use Illuminate\Support\LazyCollection;
use PKP\context\Context;
use PKP\core\Core;
use PKP\core\PKPApplication;
use PKP\db\DAORegistry;
use PKP\file\TemporaryFileManager;
use PKP\log\event\PKPSubmissionEventLogEntry;
use PKP\observers\events\PublicationPublished;
use PKP\observers\events\PublicationUnpublished;
use PKP\plugins\Hook;
use PKP\security\Validation;
use PKP\services\PKPSchemaService;
use PKP\submission\Genre;
use PKP\submission\PKPSubmission;
use PKP\userGroup\UserGroup;
use PKP\validation\ValidatorFactory;
abstract class Repository
{
/** @var DAO */
public $dao;
/** @var string $schemaMap The name of the class to map this entity to its schema */
public $schemaMap = maps\Schema::class;
/** @var Request */
protected $request;
/** @var PKPSchemaService<Publication> */
protected $schemaService;
public function __construct(DAO $dao, Request $request, PKPSchemaService $schemaService)
{
$this->dao = $dao;
$this->request = $request;
$this->schemaService = $schemaService;
}
/** @copydoc DAO::newDataObject() */
public function newDataObject(array $params = []): Publication
{
$object = $this->dao->newDataObject();
if (!empty($params)) {
$object->setAllData($params);
}
return $object;
}
/** @copydoc DAO::exists() */
public function exists(int $id, int $submissionId = null): bool
{
return $this->dao->exists($id, $submissionId);
}
/** @copydoc DAO::get() */
public function get(int $id, int $submissionId = null): ?Publication
{
return $this->dao->get($id, $submissionId);
}
/** @copydoc DAO::getCollector() */
public function getCollector(): Collector
{
return app(Collector::class);
}
/**
* Get an instance of the map class for mapping
* publications to their schema
*
* @param LazyCollection<int,UserGroup> $userGroups
* @param Genre[] $genres
*/
public function getSchemaMap(Submission $submission, LazyCollection $userGroups, array $genres): maps\Schema
{
return app('maps')->withExtensions(
$this->schemaMap,
[
'submission' => $submission,
'userGroups' => $userGroups,
'genres' => $genres,
]
);
}
/** @copydoc DAO:: getIdsBySetting()*/
public function getIdsBySetting(string $settingName, $settingValue, int $contextId): Enumerable
{
return $this->dao->getIdsBySetting($settingName, $settingValue, $contextId);
}
/** @copydoc DAO:: getDateBoundaries()*/
public function getDateBoundaries(Collector $query): object
{
return $this->dao->getDateBoundaries($query);
}
/**
* Validate properties for a publication
*
* Perform validation checks on data used to add or edit a publication.
*
* @param Publication|null $publication The publication being edited. Pass `null` if creating a new publication
* @param array $props A key/value array with the new data to validate
*
* @return array A key/value array with validation errors. Empty if no errors
*/
public function validate(?Publication $publication, array $props, Submission $submission, Context $context): array
{
$allowedLocales = $context->getSupportedSubmissionLocales();
$primaryLocale = $submission->getLocale();
$errors = [];
$validator = ValidatorFactory::make(
$props,
$this->schemaService->getValidationRules($this->dao->schema, $allowedLocales),
$this->getErrorMessageOverrides(),
);
ValidatorFactory::required(
$validator,
$publication,
$this->schemaService->getRequiredProps($this->dao->schema),
$this->schemaService->getMultilingualProps($this->dao->schema),
$allowedLocales,
$primaryLocale
);
ValidatorFactory::allowedLocales($validator, $this->schemaService->getMultilingualProps($this->dao->schema), $allowedLocales);
// The submissionId must match an existing submission
if (isset($props['submissionId'])) {
$validator->after(function ($validator) use ($props) {
if (!$validator->errors()->get('submissionId')) {
$submission = Repo::submission()->get($props['submissionId']);
if (!$submission) {
$validator->errors()->add('submissionId', __('publication.invalidSubmission'));
}
}
});
}
// A title must be provided if the submission is not still in progress
if (!$submission->getData('submissionProgress')) {
$validator->after(function ($validator) use ($props, $publication, $primaryLocale) {
$title = isset($props['title']) && isset($props['title'][$primaryLocale])
? $props['title'][$primaryLocale]
: $publication?->getData('title', $primaryLocale);
if (empty($title)) {
$validator->errors()->add('title.' . $primaryLocale, __('validator.required'));
}
});
}
// The urlPath must not be used in a publication attached to
// any submission other than this publication's submission
if (strlen($props['urlPath'] ?? '')) {
$validator->after(function ($validator) use ($publication, $props) {
if (!$validator->errors()->get('urlPath')) {
if (ctype_digit((string) $props['urlPath'])) {
$validator->errors()->add('urlPath', __('publication.urlPath.numberInvalid'));
return;
}
// If there is no submissionId the validator will throw it back anyway
if (is_null($publication) && !empty($props['submissionId'])) {
$submission = Repo::submission()->get($props['submissionId']);
} elseif (!is_null($publication)) {
$submission = Repo::submission()->get($publication->getData('submissionId'));
}
// If there's no submission we can't validate but the validator should
// fail anyway, so we can return without setting a separate validation
// error.
if (!$submission) {
return;
}
if ($this->dao->isDuplicateUrlPath($props['urlPath'], $submission->getId(), $submission->getData('contextId'))) {
$validator->errors()->add('urlPath', __('publication.urlPath.duplicate'));
}
}
});
}
// If a new file has been uploaded, check that the temporary file exists and
// the current user owns it
$user = Application::get()->getRequest()->getUser();
ValidatorFactory::temporaryFilesExist(
$validator,
['coverImage'],
['coverImage'],
$props,
$allowedLocales,
$user ? $user->getId() : null
);
if ($validator->fails()) {
$errors = $this->schemaService->formatValidationErrors($validator->errors());
}
Hook::call('Publication::validate', [&$errors, $publication, $props, $allowedLocales, $primaryLocale]);
return $errors;
}
/**
* Validate a publication against publishing requirements
*
* This validation check should return zero errors before
* publishing a publication.
*
* It should not be necessary to repeat validation rules from
* self::validate(). These rules should be applied during all add
* or edit actions.
*
* This additional check should be used when a journal or press
* wants to enforce particular publishing requirements, such as
* requiring certain metadata or other information.
*
* @param array $allowedLocales The context's supported submission locales
* @param string $primaryLocale The submission's primary locale
*/
public function validatePublish(Publication $publication, Submission $submission, array $allowedLocales, string $primaryLocale): array
{
$errors = [];
// Don't allow declined submissions to be published
if ($submission->getData('status') === PKPSubmission::STATUS_DECLINED) {
$errors['declined'] = __('publication.required.declined');
}
// Don't allow a publication to be published before passing the review stage
if ($submission->getData('stageId') <= WORKFLOW_STAGE_ID_EXTERNAL_REVIEW) {
$errors['reviewStage'] = __('publication.required.reviewStage');
}
Hook::call('Publication::validatePublish', [&$errors, $publication, $submission, $allowedLocales, $primaryLocale]);
return $errors;
}
/** @copydoc DAO::insert() */
public function add(Publication $publication): int
{
$publication->stampModified();
$publicationId = $this->dao->insert($publication);
$publication = Repo::publication()->get($publicationId);
$submission = Repo::submission()->get($publication->getData('submissionId'));
// Move uploaded files into place and update the settings
if ($publication->getData('coverImage')) {
$userId = $this->request->getUser() ? $this->request->getUser()->getId() : null;
$submissionContext = $this->request->getContext();
if ($submissionContext->getId() !== $submission->getData('contextId')) {
$submissionContext = Services::get('context')->get($submission->getData('contextId'));
}
$supportedLocales = $submissionContext->getSupportedSubmissionLocales();
foreach ($supportedLocales as $localeKey) {
if (!array_key_exists($localeKey, $publication->getData('coverImage'))) {
continue;
}
$value[$localeKey] = $this->_saveFileParam($publication, $submission, $publication->getData('coverImage', $localeKey), 'coverImage', $userId, $localeKey, true);
}
$this->edit($publication, ['coverImage' => $value]);
}
Hook::call('Publication::add', [&$publication]);
// Update a submission's status based on the status of its publications
Repo::submission()->updateStatus($submission);
return $publication->getId();
}
/**
* Create a new version of a publication
*
* Makes a copy of an existing publication, without the datePublished,
* and makes copies of all associated objects.
*/
public function version(Publication $publication): int
{
$newPublication = clone $publication;
$newPublication->setData('id', null);
$newPublication->setData('datePublished', null);
$newPublication->setData('status', Submission::STATUS_QUEUED);
$newPublication->setData('version', $publication->getData('version') + 1);
$newPublication->stampModified();
$request = Application::get()->getRequest();
$context = $request->getContext();
if ($context->getData(Context::SETTING_DOI_VERSIONING)) {
$newPublication->setData('doiId', null);
}
$newId = $this->add($newPublication);
$newPublication = Repo::publication()->get($newId);
$authors = $publication->getData('authors');
if (!empty($authors)) {
foreach ($authors as $author) {
$newAuthor = clone $author;
$newAuthor->setData('id', null);
$newAuthor->setData('publicationId', $newPublication->getId());
$newAuthorId = Repo::author()->add($newAuthor);
if ($author->getId() === $publication->getData('primaryContactId')) {
$this->edit($newPublication, ['primaryContactId' => $newAuthorId]);
}
}
}
if (!empty($newPublication->getData('citationsRaw'))) {
$citationDao = DAORegistry::getDAO('CitationDAO'); /** @var \PKP\citation\CitationDAO $citationDao */
$citationDao->importCitations($newPublication->getId(), $newPublication->getData('citationsRaw'));
}
$newPublication = Repo::publication()->get($newPublication->getId());
Hook::call('Publication::version', [&$newPublication, $publication]);
$submission = Repo::submission()->get($newPublication->getData('submissionId'));
$eventLog = Repo::eventLog()->newDataObject([
'assocType' => PKPApplication::ASSOC_TYPE_SUBMISSION,
'assocId' => $submission->getId(),
'eventType' => PKPSubmissionEventLogEntry::SUBMISSION_LOG_CREATE_VERSION,
'userId' => Validation::loggedInAs() ?? $request->getUser()?->getId(),
'message' => 'publication.event.versionCreated',
'isTranslated' => false,
'dateLogged' => Core::getCurrentDate(),
]);
Repo::eventLog()->add($eventLog);
return $newPublication->getId();
}
/** @copydoc DAO::update() */
public function edit(Publication $publication, array $params): Publication
{
$submission = Repo::submission()->get($publication->getData('submissionId'));
$userId = $this->request->getUser()?->getId();
// Move uploaded files into place and update the params
if (array_key_exists('coverImage', $params)) {
$submissionContext = $this->request->getContext();
if ($submissionContext->getId() !== $submission->getData('contextId')) {
$submissionContext = Services::get('context')->get($submission->getData('contextId'));
}
$supportedLocales = $submissionContext->getSupportedSubmissionLocales();
foreach ($supportedLocales as $localeKey) {
if (!array_key_exists($localeKey, $params['coverImage'])) {
continue;
}
$params['coverImage'][$localeKey] = $this->_saveFileParam($publication, $submission, $params['coverImage'][$localeKey], 'coverImage', $userId, $localeKey, true);
}
}
$newPublication = Repo::publication()->newDataObject(array_merge($publication->_data, $params));
$newPublication->stampModified();
Hook::call('Publication::edit', [&$newPublication, $publication, $params, $this->request]);
$this->dao->update($newPublication, $publication);
$newPublication = Repo::publication()->get($newPublication->getId());
$submission = Repo::submission()->get($newPublication->getData('submissionId'));
// Log an event when publication data is updated
$eventLog = Repo::eventLog()->newDataObject([
'assocType' => PKPApplication::ASSOC_TYPE_SUBMISSION,
'assocId' => $submission->getId(),
'eventType' => PKPSubmissionEventLogEntry::SUBMISSION_LOG_METADATA_UPDATE,
'userId' => Validation::loggedInAs() ?? $userId,
'message' => 'submission.event.general.metadataUpdated',
'isTranslated' => false,
'dateLogged' => Core::getCurrentDate(),
]);
Repo::eventLog()->add($eventLog);
return $newPublication;
}
/**
* Publish a publication
*
* This method performs all actions needed when publishing an item, such
* as setting metadata, logging events, updating the search index, etc.
*
* @throws \Exception
*
* @see self::setStatusOnPublish()
*/
public function publish(Publication $publication)
{
$newPublication = clone $publication;
$newPublication->stampModified();
$this->setStatusOnPublish($newPublication);
// Set the copyright and license information
$submission = Repo::submission()->get($newPublication->getData('submissionId'));
$itsPublished = ($newPublication->getData('status') === PKPSubmission::STATUS_PUBLISHED);
if ($itsPublished && !$newPublication->getData('copyrightHolder')) {
$newPublication->setData(
'copyrightHolder',
$submission->_getContextLicenseFieldValue(
null,
PKPSubmission::PERMISSIONS_FIELD_COPYRIGHT_HOLDER,
$newPublication
)
);
}
if ($itsPublished && !$newPublication->getData('copyrightYear')) {
$newPublication->setData(
'copyrightYear',
$submission->_getContextLicenseFieldValue(
null,
PKPSubmission::PERMISSIONS_FIELD_COPYRIGHT_YEAR,
$newPublication
)
);
}
if ($itsPublished && !$newPublication->getData('licenseUrl')) {
$newPublication->setData(
'licenseUrl',
$submission->_getContextLicenseFieldValue(
null,
PKPSubmission::PERMISSIONS_FIELD_LICENSE_URL,
$newPublication
)
);
}
Hook::call('Publication::publish::before', [&$newPublication, $publication]);
$this->dao->update($newPublication);
$newPublication = Repo::publication()->get($newPublication->getId());
$submission = Repo::submission()->get($newPublication->getData('submissionId'));
// Update a submission's status based on the status of its publications
if ($newPublication->getData('status') !== $publication->getData('status')) {
Repo::submission()->updateStatus($submission);
$submission = Repo::submission()->get($submission->getId());
}
$msg = ($newPublication->getData('status') === Submission::STATUS_SCHEDULED) ? 'publication.event.scheduled' : 'publication.event.published';
// Log an event when publication is published. Adjust the message depending
// on whether this is the first publication or a subsequent version
if (count($submission->getData('publications')) > 1) {
$msg = ($newPublication->getData('status') === Submission::STATUS_SCHEDULED) ? 'publication.event.versionScheduled' : 'publication.event.versionPublished';
}
$eventLog = Repo::eventLog()->newDataObject([
'assocType' => PKPApplication::ASSOC_TYPE_SUBMISSION,
'assocId' => $submission->getId(),
'eventType' => PKPSubmissionEventLogEntry::SUBMISSION_LOG_METADATA_PUBLISH,
'userId' => Validation::loggedInAs() ?? $this->request->getUser()?->getId(),
'message' => $msg,
'isTranslated' => false,
'dateLogged' => Core::getCurrentDate()
]);
Repo::eventLog()->add($eventLog);
// Mark DOIs stale (if applicable).
if ($newPublication->getData('status') === Submission::STATUS_PUBLISHED) {
$staleDoiIds = Repo::doi()->getDoisForSubmission($newPublication->getData('submissionId'));
Repo::doi()->markStale($staleDoiIds);
}
Hook::call(
'Publication::publish',
[
&$newPublication,
$publication,
$submission
]
);
$context = $submission->getData('contextId') === Application::get()->getRequest()->getContext()?->getId()
? Application::get()->getRequest()->getContext()
: Services::get('context')->get($submission->getData('contextId'));
event(new PublicationPublished($newPublication, $publication, $submission, $context));
}
/**
* Set the status when an item is published
*
* Each application may handle publishing in a different way. Implement this method
* in an app-specific child class by assigning `status` and `datePublished` for this
* publication.
*
* This method should be called by self::publish().
*/
abstract protected function setStatusOnPublish(Publication $publication);
/**
* Unpublish a publication
*
* This method performs all actions needed when unpublishing an item, such
* as changing the status, logging events, updating the search index, etc.
*
* @see self::setStatusOnPublish()
*/
public function unpublish(Publication $publication)
{
$newPublication = clone $publication;
$newPublication->setData('status', Submission::STATUS_QUEUED);
$newPublication->stampModified();
Hook::call(
'Publication::unpublish::before',
[
&$newPublication,
$publication
]
);
$this->dao->update($newPublication);
$newPublication = Repo::publication()->get($newPublication->getId());
$submission = Repo::submission()->get($newPublication->getData('submissionId'));
// Update a submission's status based on the status of its publications
if ($newPublication->getData('status') !== $publication->getData('status')) {
Repo::submission()->updateStatus($submission);
$submission = Repo::submission()->get($submission->getId());
}
// Log an event when publication is unpublished. Adjust the message depending
// on whether this is the first publication or a subsequent version
$msg = 'publication.event.unpublished';
if (count($submission->getData('publications')) > 1) {
$msg = 'publication.event.versionUnpublished';
}
// Mark DOIs stable (if applicable).
if ($submission->getData('status') !== Submission::STATUS_PUBLISHED) {
$staleDoiIds = Repo::doi()->getDoisForSubmission($newPublication->getData('submissionId'));
Repo::doi()->markStale($staleDoiIds);
}
$eventLog = Repo::eventLog()->newDataObject([
'assocType' => PKPApplication::ASSOC_TYPE_SUBMISSION,
'assocId' => $submission->getId(),
'eventType' => PKPSubmissionEventLogEntry::SUBMISSION_LOG_METADATA_UNPUBLISH,
'userId' => Validation::loggedInAs() ?? $this->request->getUser()?->getId(),
'message' => $msg,
'isTranslated' => false,
'dateLogged' => Core::getCurrentDate()
]);
Repo::eventLog()->add($eventLog);
Hook::call(
'Publication::unpublish',
[
&$newPublication,
$publication,
$submission
]
);
$context = $submission->getData('contextId') === Application::get()->getRequest()->getContext()->getId()
? Application::get()->getRequest()->getContext()
: Services::get('context')->get($submission->getData('contextId'));
event(new PublicationUnpublished($newPublication, $publication, $submission, $context));
}
/** @copydoc DAO::delete() */
public function delete(Publication $publication)
{
Hook::call('Publication::delete::before', [&$publication]);
$submission = Repo::submission()->get($publication->getData('submissionId'));
$sectionId = $publication->getData(Application::getSectionIdPropName());
$section = $sectionId ? Repo::section()->get($sectionId) : null;
$this->dao->delete($publication);
// Update a submission's status based on the status of its remaining publications
$submission = Repo::submission()->get($publication->getData('submissionId'));
Repo::submission()->updateStatus($submission, null, $section);
Hook::call('Publication::delete', [&$publication]);
}
/**
* Handle a publication setting for an uploaded file
*
* - Moves the temporary file to the public directory
* - Resets the param value to what is expected to be stored in the db
* - If a null value is passed, deletes any existing file
*
* This method is protected because all operations which edit publications should
* go through the add and edit methods in order to ensure that
* the appropriate hooks are fired.
*
* @param Publication $publication The publication being edited
* @param Submission $submission The submission this publication is part of
* @param mixed $value The param value to be saved. Contains the temporary
* file ID if a new file has been uploaded.
* @param string $settingName The name of the setting to save, typically used
* in the filename.
* @param int $userId ID of the user who owns the temporary file
* @param string $localeKey Optional. Pass if the setting is multilingual
* @param bool $isImage Optional. For image files which include alt text in value
*
* @return string|array|bool New param value or false on failure
*/
protected function _saveFileParam(
Publication $publication,
Submission $submission,
$value,
string $settingName,
int $userId,
string $localeKey = '',
bool $isImage = false
) {
// If the value is null, delete any existing unused file in the system
if (is_null($value)) {
$oldPublication = Repo::publication()->get($publication->getId());
$oldValue = $oldPublication->getData($settingName, $localeKey);
$fileName = $oldValue['uploadName'] ?? null;
if ($fileName) {
// File may be in use by other publications
$fileInUse = false;
foreach ($submission->getData('publications') as $iPublication) {
if ($publication->getId() === $iPublication->getId()) {
continue;
}
$iValue = $iPublication->getData($settingName, $localeKey);
if (!empty($iValue['uploadName']) && $iValue['uploadName'] === $fileName) {
$fileInUse = true;
continue;
}
}
if (!$fileInUse) {
$publicFileManager = new PublicFileManager();
$publicFileManager->removeContextFile($submission->getData('contextId'), $fileName);
}
}
return null;
}
// Check if there is something to upload
if (empty($value['temporaryFileId'])) {
return $value;
}
// Get the submission context
$submissionContext = $this->request->getContext();
if ($submissionContext->getId() !== $submission->getData('contextId')) {
$submissionContext = Services::get('context')->get($submission->getData('contextId'));
}
$temporaryFileManager = new TemporaryFileManager();
$temporaryFile = $temporaryFileManager->getFile((int) $value['temporaryFileId'], $userId);
$fileNameBase = join('_', ['submission', $submission->getId(), $publication->getId(), $settingName]); // eg - submission_1_1_coverImage
$fileName = Services::get('context')->moveTemporaryFile($submissionContext, $temporaryFile, $fileNameBase, $userId, $localeKey);
if ($fileName) {
if ($isImage) {
return [
'altText' => !empty($value['altText']) ? $value['altText'] : '',
'dateUploaded' => Core::getCurrentDate(),
'uploadName' => $fileName,
];
} else {
return [
'dateUploaded' => Core::getCurrentDate(),
'uploadName' => $fileName,
];
}
}
return null;
}
/**
* Get error message overrides for the validator
*/
protected function getErrorMessageOverrides(): array
{
return [
'locale.regex' => __('validator.localeKey'),
'datePublished.date_format' => __('publication.datePublished.errorFormat'),
'urlPath.regex' => __('validator.alpha_dash_period'),
];
}
/**
* Create all DOIs associated with the publication.
*/
abstract protected function createDois(Publication $newPublication): void;
}
+167
View File
@@ -0,0 +1,167 @@
<?php
/**
* @file classes/publication/maps/Schema.php
*
* Copyright (c) 2014-2020 Simon Fraser University
* Copyright (c) 2000-2020 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class Schema
*
* @brief Map publications to the properties defined in the publication schema
*/
namespace PKP\publication\maps;
use APP\core\Request;
use APP\facades\Repo;
use APP\publication\Publication;
use APP\submission\Submission;
use Illuminate\Support\Enumerable;
use Illuminate\Support\LazyCollection;
use PKP\citation\CitationDAO;
use PKP\context\Context;
use PKP\db\DAORegistry;
use PKP\services\PKPSchemaService;
use PKP\submission\Genre;
class Schema extends \PKP\core\maps\Schema
{
/** */
public Enumerable $collection;
/** */
public string $schema = PKPSchemaService::SCHEMA_PUBLICATION;
/** @var Submission */
public $submission;
/** @var bool */
public $anonymize;
/** @var LazyCollection UserGroup The user groups for this context. */
public $userGroups;
/** @var Genre[] The file genres for this context. */
public array $genres;
public function __construct(Submission $submission, LazyCollection $userGroups, array $genres, Request $request, Context $context, PKPSchemaService $schemaService)
{
parent::__construct($request, $context, $schemaService);
$this->submission = $submission;
$this->userGroups = $userGroups;
$this->genres = $genres;
}
/**
* Map a publication
*
* Includes all properties in the publication schema.
*/
public function map(Publication $item, bool $anonymize = false): array
{
return $this->mapByProperties($this->getProps(), $item, $anonymize);
}
/**
* Summarize a publication
*
* Includes properties with the apiSummary flag in the publication schema.
*/
public function summarize(Publication $item, bool $anonymize = false): array
{
return $this->mapByProperties($this->getSummaryProps(), $item, $anonymize);
}
/**
* Map a collection of Publications
*
* @see self::map
*/
public function mapMany(Enumerable $collection, bool $anonymize = false): Enumerable
{
$this->collection = $collection;
return $collection->map(function ($item) use ($anonymize) {
return $this->map($item, $anonymize);
});
}
/**
* Summarize a collection of Publications
*
* @see self::summarize
*/
public function summarizeMany(Enumerable $collection, bool $anonymize = false): Enumerable
{
$this->collection = $collection;
return $collection->map(function ($item) use ($anonymize) {
return $this->summarize($item, $anonymize);
});
}
/**
* Map schema properties of a Publication to an assoc array
*/
protected function mapByProperties(array $props, Publication $publication, bool $anonymize): array
{
$this->anonymize = $anonymize;
$output = [];
foreach ($props as $prop) {
switch ($prop) {
case '_href':
$output[$prop] = $this->getApiUrl(
'submissions/' . $publication->getData('submissionId') . '/publications/' . $publication->getId(),
$this->context->getData('urlPath')
);
break;
case 'authors':
if ($this->anonymize) {
$output[$prop] = [];
} else {
$output[$prop] = Repo::author()->getSchemaMap()->summarizeMany($publication->getData('authors'))->values();
}
break;
case 'authorsString':
$output[$prop] = $this->anonymize ? '' : $publication->getAuthorString($this->userGroups);
break;
case 'authorsStringIncludeInBrowse':
$output[$prop] = $this->anonymize ? '' : $publication->getAuthorString($this->userGroups, true);
break;
case 'authorsStringShort':
$output[$prop] = $this->anonymize ? '' : $publication->getShortAuthorString();
break;
case 'categoryIds':
$output[$prop] = $publication->getData('categoryIds');
break;
case 'citations':
$citationDao = DAORegistry::getDAO('CitationDAO'); /** @var CitationDAO $citationDao */
$output[$prop] = array_map(
function ($citation) {
return $citation->getCitationWithLinks();
},
$citationDao->getByPublicationId($publication->getId())->toArray()
);
break;
case 'doiObject':
if ($publication->getData('doiObject')) {
$retVal = Repo::doi()->getSchemaMap()->summarize($publication->getData('doiObject'));
} else {
$retVal = null;
}
$output[$prop] = $retVal;
break;
case 'fullTitle':
$output[$prop] = $publication->getFullTitles('html');
break;
default:
$output[$prop] = $publication->getData($prop);
break;
}
}
return $output;
}
}