first commit
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user