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
+143
View File
@@ -0,0 +1,143 @@
<?php
/**
* @file classes/doi/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 DOI
*/
namespace PKP\doi;
use APP\doi\DAO;
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 Doi
*/
class Collector implements CollectorInterface
{
/** @var DAO */
public $dao;
public ?array $contextIds = null;
public ?int $count = 30;
public ?int $offset = 0;
public ?array $statuses = null;
public ?string $identifier = null;
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 DOI by one or more contexts
*/
public function filterByContextIds(array $contextIds): self
{
$this->contextIds = $contextIds;
return $this;
}
/**
* Filter by one or more of the DOI_STATUS_* constants
*/
public function filterByStatus(array $statuses): self
{
$this->statuses = $statuses;
return $this;
}
/**
* Filter by actual identifier (DOI) or the DOI object
*/
public function filterByIdentifier(string $identifier): self
{
$this->identifier = $identifier;
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
{
$q = DB::table($this->dao->table, 'd')
->select(['d.*'])
->when($this->contextIds != null, function (Builder $q) {
$q->whereIn('d.context_id', $this->contextIds);
})
->when($this->statuses != null, function (Builder $q) {
$q->whereIn('d.status', $this->statuses);
})
->when($this->identifier !== null, function (Builder $q) {
$q->where('d.doi', '=', $this->identifier);
})
->when(!empty($this->count), function (Builder $q) {
$q->limit($this->count);
})
->when(!empty($this->offset), function (Builder $q) {
$q->offset($this->count);
});
Hook::call('Doi::Collector', [&$q, $this]);
return $q;
}
}
+191
View File
@@ -0,0 +1,191 @@
<?php
/**
* @file classes/doi/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
*
* @ingroup doi
*
* @see Doi
*
* @brief Operations for retrieving and modifying Doi objects.
*/
namespace PKP\doi;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\LazyCollection;
use PKP\context\Context;
use PKP\core\EntityDAO;
use PKP\core\traits\EntityWithParent;
use PKP\services\PKPSchemaService;
/**
* @template T of Doi
* @extends EntityDAO<T>
*/
abstract class DAO extends EntityDAO
{
use EntityWithParent;
/** @copydoc EntityDAO::$schema */
public $schema = PKPSchemaService::SCHEMA_DOI;
/** @copydoc EntityDAO::$table */
public $table = 'dois';
/** @copydoc EntityDAO::$settingsTable */
public $settingsTable = 'doi_settings';
/** @copydoc EntityDAO::$primaryKeyColumn */
public $primaryKeyColumn = 'doi_id';
/** @copydoc EntityDAO::$primaryTableColumns */
public $primaryTableColumns = [
'id' => 'doi_id',
'contextId' => 'context_id',
'doi' => 'doi',
'status' => 'status'
];
/**
* Get the parent object ID column name
*/
public function getParentColumn(): string
{
return 'context_id';
}
/**
* Instantiate a new DataObject
*/
public function newDataObject(): Doi
{
return App::make(Doi::class);
}
/**
* Get the number of DOIs matching the configured query
*/
public function getCount(Collector $query): int
{
return $query
->getQueryBuilder()
->select('d.' . $this->primaryKeyColumn)
->get()
->count();
}
/**
* Get a list of ids matching the configured query
*
* @return Collection<int,int>
*/
public function getIds(Collector $query): Collection
{
return $query
->getQueryBuilder()
->select('d.' . $this->primaryKeyColumn)
->pluck('d.' . $this->primaryKeyColumn);
}
/**
* Get a collection of DOIs 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->doi_id => $this->fromRow($row);
}
});
}
/**
* @copydoc EntityDAO::fromRow()
*/
public function fromRow(object $row): Doi
{
/** @var Doi */
$doi = parent::fromRow($row);
if (empty($doi->getData('doi'))) {
$doi->setData('resolvingUrl', '');
} else {
$doi->setData('resolvingUrl', $doi->getResolvingUrl());
}
return $doi;
}
/**
* @copydoc EntityDAO::insert()
*/
public function insert(Doi $doi): int
{
return parent::_insert($doi);
}
/**
* @copydoc EntityDAO::update()
*/
public function update(Doi $doi)
{
parent::_update($doi);
}
/**
* @copydoc EntityDAO::delete()
*/
public function delete(Doi $doi)
{
parent::_delete($doi);
}
/**
* Set DOIs as stale if they have been submitted or registered
*/
public function markStale(array $doiIds)
{
$q = DB::table($this->table, 'd');
$updatableStatuses = [
Doi::STATUS_SUBMITTED,
Doi::STATUS_REGISTERED
];
$q->whereIn('d.doi_id', $doiIds)
->whereIn('d.status', $updatableStatuses)
->update(['status' => Doi::STATUS_STALE]);
}
/**
* Set DOIs as submitted once they have been added to the queue for processing
*
*/
public function markSubmitted(array $doiIds)
{
$q = DB::table($this->table, 'd');
$q->whereIn('d.doi_id', $doiIds)
->update(['status' => Doi::STATUS_SUBMITTED]);
}
/**
* Gets all depositable submission IDs along with all associated DOI IDs for use in DOI bulk deposit jobs.
* This method is used to collect all valid submissions/IDs in a single query specifically for use with
* queued jobs for depositing DOIs with a registration agency.
*
*/
abstract public function getAllDepositableSubmissionIds(Context $context): Collection;
}
+124
View File
@@ -0,0 +1,124 @@
<?php
/**
* @defgroup doi Doi
* Implements DOI used as persistent identifiers.
*/
/**
* @file classes/doi/Doi.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 Doi
*
* @ingroup doi
*
* @see DoiDAO
*
* @brief Basic class describing a DOI.
*/
namespace PKP\doi;
use PKP\core\DataObject;
class Doi extends DataObject
{
public const STATUS_UNREGISTERED = 1;
public const STATUS_SUBMITTED = 2;
public const STATUS_REGISTERED = 3;
public const STATUS_ERROR = 4;
public const STATUS_STALE = 5;
/**
* Formats and URL encodes the DOI
*
*/
public function getResolvingUrl(): string
{
return 'https://doi.org/' . $this->_doiURLEncode($this->getData('doi'));
}
//
// Get/set methods
//
/**
* Get ID of context.
*
* @return int
*/
public function getContextId()
{
return $this->getData('contextId');
}
/**
* Set ID of context.
*
* @param int $contextId
*/
public function setContextId($contextId)
{
$this->setData('contextId', $contextId);
}
/**
* Get DOI for this DOI
*
* @return string
*/
public function getDoi()
{
return $this->getData('doi');
}
/**
* Set DOI for this DOI
*
* @param string $doi
*/
public function setDoi($doi)
{
$this->setData('doi', $doi);
}
/**
* Get status for this DOI
*
* @return int
*/
public function getStatus()
{
return $this->getData('status');
}
/**
* Set status for this DOI
*
* @param int $status
*/
public function setStatus($status)
{
$this->setData('status', $status);
}
/**
* Encode DOI according to ANSI/NISO Z39.84-2005, Appendix E.
*
*
*/
protected function _doiURLEncode(string $pubId): string
{
$search = ['%', '"', '#', ' ', '<', '>', '{'];
$replace = ['%25', '%22', '%23', '%20', '%3c', '%3e', '%7b'];
return str_replace($search, $replace, $pubId);
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\doi\Doi', '\Doi');
}
+95
View File
@@ -0,0 +1,95 @@
<?php
/**
* @file classes/doi/DoiGenerator.php
*
* Copyright (c) 2014-2022 Simon Fraser University
* Copyright (c) 2000-2022 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class DoiGenerator
*
* @brief A utility class for generating DOI suffixes using the Cool DOIs pattern, which generates opaque, but easy to read suffixes.
*
* @see https://blog.datacite.org/cool-dois/
*/
namespace PKP\doi;
use Dflydev\Base32\Crockford\Crockford;
class DoiGenerator
{
// 32 by the factor of 6
protected const UPPER_LIMIT = 1073741823;
/**
* Constructs a DOI with an 8-character suffix, using a Crockford Base 32 algorithm
* to generate the suffix.
*
*/
public static function encodeSuffix(): string
{
$number = random_int(1, self::UPPER_LIMIT);
return self::base32EncodeSuffix($number);
}
/**
* Returns the decoded int used to generate the suffix after validating the two-digit checksum
*
* @return int|null Returns null if checksum is invalid
*/
public static function decodeSuffix(string $suffix): ?int
{
$suffix = strtoupper($suffix);
$suffixParts = str_split($suffix, 6);
$encodedString = $suffixParts[0];
$checksum = $suffixParts[1];
$decodedSuffix = Crockford::decode($encodedString);
$isSuffixValid = self::verifySuffixChecksum($decodedSuffix, $checksum);
return $isSuffixValid ? $decodedSuffix : null;
}
/**
* Encodes suffix as 8-digit base32 encoded string where the final two numbers are a checksum.
*
* E.g. DDDDDDYY where 'D' is a base32 encoded character and 'YY' is the checksum.
*
* @param int $number A random number between 1 and 1073741823 (UPPER_LIMIT). Used as seed for encoding suffix.
*/
protected static function base32EncodeSuffix(int $number): string
{
// Initial base32 encoded string (up to 6 characters max)
$encodedNumber = strtolower(Crockford::encode($number));
// Add checksum at end of string, calculated as modulo 97-10 (ISO 7064)
$remainder = self::calculateChecksum($number);
$payload = $encodedNumber . sprintf('%02d', $remainder);
return str_pad($payload, 8, '0', STR_PAD_LEFT);
}
/**
* Verifies the provided checksum was generated from the number provided.
*
* @param int $number The integer decoded form the base 32 suffix. Original number used to generate suffix.
* @param int $checksum The two-digit checksum (last two digits of suffix)
*/
protected static function verifySuffixChecksum(int $number, int $checksum): bool
{
return $checksum === self::calculateChecksum($number);
}
/**
* Checksum calculated as modulo 97-10 (ISO 7064).
*/
protected static function calculateChecksum(int $number): int
{
return 98 - (($number * 100) % 97);
}
}
@@ -0,0 +1,92 @@
<?php
/**
* @file classes/doi/RegistrationAgencySettings.php
*
* Copyright (c) 2014-2023 Simon Fraser University
* Copyright (c) 2000-2023 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class RegistrationAgencySettings
*
* @ingroup doi
*
* @brief Base class for registration agency plugin settings management
*/
namespace PKP\doi;
use APP\core\Services;
use APP\plugins\IDoiRegistrationAgency;
use Illuminate\Validation\Validator;
use PKP\components\forms\Field;
use PKP\context\Context;
use PKP\plugins\Hook;
use PKP\plugins\Plugin;
use PKP\services\interfaces\EntityWriteInterface;
use PKP\services\PKPSchemaService;
use PKP\validation\ValidatorFactory;
abstract class RegistrationAgencySettings
{
protected IDoiRegistrationAgency|Plugin $agencyPlugin;
public function __construct(IDoiRegistrationAgency $agencyPlugin)
{
$this->agencyPlugin = $agencyPlugin;
Hook::add('Schema::get::' . $this::class, [$this, 'addToSchema']);
}
public function validate(array $props): array
{
/** @var PKPSchemaService $schemaService */
$schemaService = Services::get('schema');
$validator = ValidatorFactory::make(
$props,
$schemaService->getValidationRules($this::class, []),
);
// Check required
ValidatorFactory::required(
$validator,
EntityWriteInterface::VALIDATE_ACTION_EDIT,
$schemaService->getRequiredProps($this::class),
$schemaService->getMultilingualProps($this::class),
[],
'',
);
$this->addValidationChecks($validator, $props);
if ($validator->fails()) {
$errors = $schemaService->formatValidationErrors($validator->errors());
}
return $errors ?? [];
}
abstract public function getSchema(): \stdClass;
public function addToSchema($hookname, $args): bool
{
$schema = &$args[0];
$schema = $this->getSchema();
return Hook::CONTINUE;
}
/**
* Gets plugin-specific settings field to inject into DOI registration settings form.
*
* @return Field[]
*/
abstract public function getFields(Context $context): array;
/**
* Overwrite to add additional, plugin-specific validation checks
*/
protected function addValidationChecks(Validator &$validator, array $props): void
{
}
}
+388
View File
@@ -0,0 +1,388 @@
<?php
/**
* @file classes/doi/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 DOIs.
*/
namespace PKP\doi;
use APP\core\Request;
use APP\core\Services;
use APP\facades\Repo;
use Exception;
use Illuminate\Support\Facades\App;
use PKP\context\Context;
use PKP\core\PKPString;
use PKP\doi\exceptions\DoiException;
use PKP\jobs\doi\DepositSubmission;
use PKP\plugins\Hook;
use PKP\services\PKPSchemaService;
use PKP\validation\ValidatorFactory;
abstract class Repository
{
public const TYPE_PUBLICATION = 'publication';
public const TYPE_REPRESENTATION = 'representation';
public const SUFFIX_DEFAULT = 'default';
public const SUFFIX_CUSTOM_PATTERN = 'customPattern';
public const SUFFIX_MANUAL = 'customId';
public const CUSTOM_PUBLICATION_PATTERN = 'doiPublicationSuffixPattern';
public const CUSTOM_REPRESENTATION_PATTERN = 'doiRepresentationSuffixPattern';
public const CREATION_TIME_COPYEDIT = 'copyEditCreationTime';
public const CREATION_TIME_PUBLICATION = 'publicationCreationTime';
public const CREATION_TIME_NEVER = 'neverCreationTime';
/** @var DAO $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 $request */
protected $request;
/** @var PKPSchemaService<Doi> $schemaService */
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 = []): Doi
{
$doi = $this->dao->newDataObject();
if (!empty($params)) {
$doi->setAllData($params);
}
return $doi;
}
/** @copydoc DAO::get() */
public function get(int $id, int $contextId = null): ?Doi
{
return $this->dao->get($id, $contextId);
}
/** @copydoc DAO::exists() */
public function exists(int $id, int $contextId = null): bool
{
return $this->dao->exists($id, $contextId);
}
/** @copydoc DAO::getCollector */
public function getCollector(): Collector
{
return App::make(Collector::class);
}
/**
* Get an instance of the map class for mapping
* DOIs to their schema
*/
public function getSchemaMap(): maps\Schema
{
return app('maps')->withExtensions($this->schemaMap);
}
/**
* Check if duplicate of this DOI has already been recorded across all contexts.
*/
public function isDuplicate(string $doi, ?int $excludeDoiId = null): bool
{
$collector = $this->getCollector()->filterByIdentifier($doi);
$ids = $collector->getIds();
if ($ids->count() == 0) {
return false;
}
if ($excludeDoiId === null && $ids->count() > 0) {
return true;
}
if ($ids->has($excludeDoiId) && $ids->count() < 2) {
return false;
}
return true;
}
/**
* Validate properties for a Doi
*
* Perform validation checks on data used to add or edit a Doi
*
* @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(?Doi $object, array $props): array
{
$errors = [];
$validator = ValidatorFactory::make(
$props,
$this->schemaService->getValidationRules($this->dao->schema, []),
);
// Check required fields
ValidatorFactory::required(
$validator,
$object,
$this->schemaService->getRequiredProps($this->dao->schema),
$this->schemaService->getMultilingualProps($this->dao->schema),
[],
''
);
// The contextId must match an existing context
$validator->after(function ($validator) use ($object, $props) {
if (isset($props['contextId']) && !$validator->errors()->get('contextId')) {
if (!Services::get('context')->exists($props['contextId'])) {
$validator->errors()->add('contextId', __('api.contexts.404.contextNotFound'));
}
}
// Check for duplicates across all contexts
$doiId = $object ? $object->getData('id') : null;
$doi = $props['doi'] ?? null;
if ($doi !== null && $this->isDuplicate($doi, $doiId)) {
$validator->errors()->add('doi', __('doi.editor.doiSuffixCustomIdentifierNotUnique'));
}
});
$validator->after(function ($validator) use ($object, $props) {
$doi = $props['doi'] ?? null;
if ($doi !== null && !$validator->errors()->get('doi')) {
$validRegexPattern = '/[^-._;()\/A-Za-z0-9]/';
Hook::call('Doi::suffixValidation', [&$validRegexPattern]);
$hasInvalidCharacters = PKPString::regexp_match($validRegexPattern, $doi);
if ($hasInvalidCharacters) {
$validator->errors()->add('doi', __('doi.editor.doiSuffixInvalidCharacters'));
}
}
});
if ($validator->fails()) {
$errors = $this->schemaService->formatValidationErrors($validator->errors());
}
Hook::call('Doi::validate', [&$errors, $object, $props]);
return $errors;
}
/** @copydoc DAO::insert() */
public function add(Doi $doi): int
{
$id = $this->dao->insert($doi);
Hook::call('Doi::add', [$doi]);
return $id;
}
/** @copydoc DAO:update() */
public function edit(Doi $doi, array $params)
{
$newDoi = clone $doi;
$newDoi->setAllData(array_merge($newDoi->_data, $params));
Hook::call('Doi::edit', [$newDoi, $doi, $params]);
$this->dao->update($newDoi);
}
/** @copydoc DAO::delete() */
public function delete(Doi $doi)
{
Hook::call('Doi::delete::before', [$doi]);
$this->dao->delete($doi);
Hook::call('Doi::delete', [$doi]);
}
/**
* Delete a collection of DOIs
*/
public function deleteMany(Collector $collector)
{
$dois = $collector->getMany();
foreach ($dois as $doi) {
$this->delete($doi);
}
}
/**
* Set DOIs status to Doi::STATUS_STALE, indicating the metadata has change and needs
* to be updated with the registration agency.
*/
public function markStale(array $doiIds)
{
$this->dao->markStale($doiIds);
}
/**
* Sets DOI status to Doi::STATUS_SUBMITTED, indicating the DOI has been queued to be
* deposited with a registration agency, but the actual deposit has not yet been made.
*/
public function markSubmitted(array $doiIds)
{
$this->dao->markSubmitted($doiIds);
}
/**
* Manually sets DOI status to Doi::STATUS_REGISTERED. This is used in cases where the
* DOI registration process has been complete elsewhere and needs to be recorded as
* registered locally.
*/
public function markRegistered(int $doiId)
{
$doi = $this->get($doiId);
$editParams = [
'status' => Doi::STATUS_REGISTERED,
'registrationAgency' => null
];
Hook::call('Doi::markRegistered', [&$editParams]);
$this->edit($doi, $editParams);
}
/**
* Manually sets DOI status to Doi::STATUS_UNREGISTERED.
*/
public function markUnregistered(int $doiId)
{
$doi = $this->get($doiId);
$editParams = [
'status' => Doi::STATUS_UNREGISTERED,
];
$this->edit($doi, $editParams);
}
/**
* Schedules DOI deposits with the active registration agency for all valid and
* unregistered/stale publication items. Items are added as a queued job to be
* completed asynchronously.
*/
public function depositAll(Context $context)
{
$enabledDoiTypes = $context->getData(Context::SETTING_ENABLED_DOI_TYPES) ?? [];
if ($this->_checkIfSubmissionValidForDeposit($enabledDoiTypes)) {
// If there is no configured registration agency, nothing can be deposited.
$agency = $context->getConfiguredDoiAgency();
if (!$agency) {
return;
}
$submissionsCollection = $this->dao->getAllDepositableSubmissionIds($context);
$submissionData = $submissionsCollection->reduce(function ($carry, $item) {
if ($item->submission_id) {
$carry['submissionIds'][] = $item->submission_id;
}
$carry['doiIds'][] = $item->doi_id;
return $carry;
}, ['submissionIds' => [], 'doiIds' => []]);
// Schedule/queue jobs for submissions
foreach ($submissionData['submissionIds'] as $submissionId) {
dispatch(new DepositSubmission($submissionId, $context, $agency));
}
// Mark submission DOIs as submitted
Repo::doi()->markSubmitted($submissionData['doiIds']);
}
}
/**
* Checks whether a DOI object is referenced by ID on any pub objects for a given pub object type.
*
* @param string $pubObjectType One of Repo::doi()::TYPE_* constants
*/
public function isAssigned(int $doiId, string $pubObjectType): bool
{
return match ($pubObjectType) {
Repo::doi()::TYPE_PUBLICATION => Repo::publication()
->getCollector()
->filterByDoiIds([$doiId])
->getIds()
->count(),
default => false,
};
}
/**
* Creates an eight character DOI suffix
*
*/
protected function generateDefaultSuffix(): string
{
return DoiGenerator::encodeSuffix();
}
/**
* Loops over valid submission DOI types to see if any are enabled
*/
private function _checkIfSubmissionValidForDeposit(array $enabledDoiTypes): bool
{
foreach ($this->getValidSubmissionDoiTypes() as $validSubmissionDoiType) {
if (in_array($validSubmissionDoiType, $enabledDoiTypes)) {
return true;
}
}
return false;
}
/**
* Get app-specific DOI type constants to check when scheduling deposit for submissions
*/
abstract protected function getValidSubmissionDoiTypes(): array;
/**
* Gets all DOI IDs related to a submission
*
* @return array<int> DOI IDs
*/
abstract public function getDoisForSubmission(int $submissionId): array;
/**
* Compose final DOI and save to database
*
* @throws Exception
*/
protected function mintAndStoreDoi(Context $context, string $doiSuffix): int
{
$doiPrefix = $context->getData(Context::SETTING_DOI_PREFIX);
if (empty($doiPrefix)) {
throw new DoiException('doi.exceptions.missingPrefix');
}
$completedDoi = $doiPrefix . '/' . $doiSuffix;
$doiDataParams = [
'doi' => $completedDoi,
'contextId' => $context->getId()
];
$doi = $this->newDataObject($doiDataParams);
return $this->add($doi);
}
}
@@ -0,0 +1,36 @@
<?php
/**
* @file classes/doi/exceptions/DoiException.php
*
* Copyright (c) 2014-2022 Simon Fraser University
* Copyright (c) 2000-2022 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class DoiException
*
* @brief Exception for failure to perform any action on a DOI
*/
namespace PKP\doi\exceptions;
class DoiException extends \Exception
{
public const PUBLICATION_MISSING_ISSUE = 'doi.submission.issueMissing.publication';
public const REPRESENTATION_MISSING_ISSUE = 'doi.submission.issueMissing.representation';
public const INCORRECT_SUBMISSION_CONTEXT = 'doi.submission.incorrectContext';
public const INCORRECT_ISSUE_CONTEXT = 'doi.issue.incorrectContext';
public const INCORRECT_STALE_STATUS = 'doi.incorrectStaleStatus';
public const SUBMISSION_NOT_PUBLISHED = 'doi.submission.notPublished';
public const ISSUE_NOT_PUBLISHED = 'doi.issue.notPublished';
/**
* @param string $errorKey Locale key for message to send in exception
* @param string|null $itemTitle Top-level object title (submission or issue)
* @param string|null $pubObjectTitle Publication object title (publication, galley, chapter, etc.)
*/
public function __construct(string $errorKey, ?string $itemTitle = null, ?string $pubObjectTitle = null)
{
$errorMessage = __($errorKey, ['itemTitle' => $itemTitle, 'pubObjectTitle' => $pubObjectTitle]);
parent::__construct($errorMessage);
}
}
+94
View File
@@ -0,0 +1,94 @@
<?php
/**
* @file classes/doi/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 DOI to the properties defined in the Doi schema
*/
namespace PKP\doi\maps;
use Illuminate\Support\Enumerable;
use PKP\doi\Doi;
use PKP\services\PKPSchemaService;
class Schema extends \PKP\core\maps\Schema
{
/** */
public Enumerable $collection;
/** */
public string $schema = PKPSchemaService::SCHEMA_DOI;
/**
* Map a DOI
*
* Includes all properties in the Doi schema
*/
public function map(Doi $item): array
{
return $this->mapByProperties($this->getProps(), $item);
}
/**
* Summarize a DOI
*
* Includes properties with the apiSummary flag in the Doi schema
*/
public function summarize(Doi $item): array
{
return $this->mapByProperties($this->getSummaryProps(), $item);
}
/**
* Map a collection of DOIs
*
* @see self::map
*/
public function mapMany(Enumerable $collection): Enumerable
{
$this->collection = $collection;
return $collection->map(function ($item) {
return $this->map($item);
});
}
/**
* Summarize a collection of Dois
*
* @see self::summarize
*/
public function summarizeMany(Enumerable $collection): Enumerable
{
$this->collection = $collection;
return $collection->map(function ($item) {
return $this->summarize($item);
});
}
/**
* Map schema properties of a DOI to an assoc array
*/
protected function mapByProperties(array $props, Doi $item): array
{
$output = [];
foreach ($props as $prop) {
switch ($prop) {
case 'resolvingUrl':
$output[$prop] = $item->getResolvingUrl();
break;
default:
$output[$prop] = $item->getData($prop);
break;
}
}
ksort($output);
return $this->withExtensions($output, $item);
}
}