You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The way DOIs work in OJS/OMP/OPS in general was massively overhauled in 3.4, and the way registration agency plugins are treated and interact with the rest of the application as it relates to DOIs has also significantly changed from 3.3. Detailed documentation on what's new, what's needed, and why will be necessary for new developers to understand how DOIs work within the registration agency plugin ecosystem and to be able to write new registration agency plugins.
A draft of all the details related to changes/requirements for registration agency plugins can be found below. 👇
DOI Registration Agency Plugins in 3.4
The following outlines the major architectural changes to how DOIs work with plugins in OJS/OMP/OPS 3.4 and the elements necessary to create a registration agency plugin for 3.4. A plugin that interacts with the DOI functionality is now referred to as a "registration agency plugin" or agency plugin for short.
Implementation Requirements
When creating a new registration agency plugin, there are two different aspects to consider: 1) the functionality that is enforced via code (e.g. required interfaces, inherited methods, etc.) and 2) functionality that is not enforced via code (e.g. functions/hooks that are dictated by convention and won't raise an error in your IDE).
The main plugin must be a GenericPlugin and implement the IDoiRegistrationAgency interface
setEnabled()
Base implementation defined in LazyLoadPlugin::setEnabled()
A registration agency plugin can be set as the configured agency plugin at the context level. When the plugin is disabled, if the plugin is currently set as the configured agency plugin, it should be removed, e.g.
if ($context->getData(Context::SETTING_CONFIGURED_REGISTRATION_AGENCY) === $this->getName()) {
$context->setData(Context::SETTING_CONFIGURED_REGISTRATION_AGENCY, Context::SETTING_NO_REGISTRATION_AGENCY);
$contextDao->updateObject($context);
}
exportSubmission()
The export methods are enforced by IDoiRegistrationAgency but the shape of the array returned is not. It should return array with the following shape:
The deposit methods are enforced by IDORegistrationAgency but the shape of the array returned is not. It should return an array with the following shape:
array{hasError: bool, responseMessage: string}
The actual depositing logic is handled via the export plugin and this method returns results to the API. The function should look something like:
Enforced by IDoiRegistrationAgency. Any agency-specific requirements for the plugin can be checked here. Will prevent exporting/depositing if the plugin is not correctly configured.
The following snippet can get the required settings from the plugin setting to include as part of the configuration check.
Should return null if not used. If a key is defined, registration or error messages can be saved/associated with individual DOI submissions. If used, the items will need to be added to the DOI schema via the Schema::get::doi hook as well as managed throughout the DOI registration lifecycle e.g. removing error messages when successfully deposited, marked registered, etc. Most of the time this should happen in-place when the status is set, except for the DOI being marked registered. The Doi::markRegistered hook should be used in this case to modify the params to be saved (see hooks and plugin initialization below).
getAllowedDoiTypes()
Enforced by IDoiRegistrationAgency. Should return an array of DOI types that are allowed to be registered with this registration agency. E.g.
Plugin initialization (registration of hooks, etc) should be abstracted out to a private pluginInitialization() function that can be called from the plugin's register() function, getExportPlugin() function (see below), or when attempting to get the export plugin via a CLI operation where plugin registration doesn't happen, e.g.
/** * @return AgencyExportPlugin */privatefunction_getExportPlugin()
{
if (empty($this->_exportPlugin)) {
$pluginCategory = 'importexport';
$pluginPathName = 'AgencyExportPlugin';
$this->_exportPlugin = PluginRegistry::getPlugin($pluginCategory, $pluginPathName);
// If being run from CLI, there is no context, so plugin initialization would not have been firedif ($this->_exportPlugin === null && !isset($_SERVER['SERVER_NAME'])) {
$this->_pluginInitialization();
$this->_exportPlugin = PluginRegistry::getPlugin($pluginCategory, $pluginPathName);
}
}
return$this->_exportPlugin;
}
pluginInitialization() should instantiate the export plugin, add it to the plugin registry, and add any hook callbacks.
Required hooks:
DoiSettingsForm::setEnabledRegistrationAgencies: Callback should be addAsRegistrationAgency() method from IDoiRegistrationAgency
DoiSetupSettingsForm::getObjectTypes: Which DOI types can be assigned to which plugins are tracked by the settings form and need to be added in the expected way. The callback should look as follows:
/** * Adds self to "allowed" list of pub object types that can be assigned DOIs for this registration agency. * * @param string $hookName DoiSetupSettingsForm::getObjectTypes * @param array $args [ * * @option array &$objectTypeOptions * ] */publicfunctionaddAllowedObjectTypes(string$hookName, array$args): bool
{
$objectTypeOptions = &$args[0];
$allowedTypes = $this->getAllowedDoiTypes();
$objectTypeOptions = array_map(function ($option) use ($allowedTypes) {
if (in_array($option['value'], $allowedTypes)) {
$option['allowedBy'][] = $this->getName();
}
return$option;
}, $objectTypeOptions);
return Hook::CONTINUE;
}
DoiListPanel::setConfig: Adds display name in DoiListPanel for agency. The call back should look as follows:
/** * Includes human-readable name of registration agency for display in conjunction with how/with whom the * DOI was registered. * * @param string $hookName DoiListPanel::setConfig * @param array $args [ * * @option $config array * ] */publicfunctionaddRegistrationAgencyName(string$hookName, array$args): bool
{
$config = &$args[0];
$config['registrationAgencyNames'][$this->_getExportPlugin()->getName()] = $this->getRegistrationAgencyName();
returnHOOK::CONTINUE;
}
Optional hooks:
Context::validate: Can be used to enforce validation rule to restrict the types of DOIs that can be registered with this agency. The system architecture by default assumes all types are allowed and any restrictions must be specified. Example from the Crossref plugin:
/** * Add validation rule to Context for restriction of allowed pubObject types for DOI registration. * * @throws \Exception */publicfunctionvalidateAllowedPubObjectTypes(string$hookName, array$args): bool
{
$errors = &$args[0];
$props = $args[2];
if (!isset($props['enabledDoiTypes'])) {
return Hook::CONTINUE;
}
$contextId = $props['id'];
if (empty($contextId)) {
thrownew \Exception('A context ID must be present to edit context settings');
}
/** @var ContextService $contextService */$contextService = Services::get('context');
$context = $contextService->get($contextId);
$enabledRegistrationAgency = $context->getConfiguredDoiAgency();
if (!$enabledRegistrationAgencyinstanceof$this) {
return Hook::CONTINUE;
}
$allowedTypes = $enabledRegistrationAgency->getAllowedDoiTypes();
if (!empty(array_diff($props['enabledDoiTypes'], $allowedTypes))) {
$errors['enabledDoiTypes'] = [__('doi.manager.settings.enabledDoiTypes.error')];
}
return Hook::CONTINUE;
}
Schema::get::doi: This can be used to add any additional data to be stored alongside DOIs. This can include any agency-specific data, or registration, error messages, e.g.
Doi::markRegistered: If any registration, error, or any other custom messages should be removed when a DOI is marked as registered, that data should be added here, e.g.
The param names must be the same as those added to the schema.
Plugin settings, getSettingsObject(), and RegistrationAgencySettings
Registration agency plugin settings are integrated with the rest of the DOI settings/options rather than being managed through the plugin settings directly. This is managed by an agency-specific settings class that getSetingsObject() should return, e.g.
where AgencySettings is the plugin-specific class that inherits from RegistrationAgencySettings.
RegistrationAgencySettings manages much of the logic for creating the settings directly, but three abstract methods must be overridden in the child class:
getSchema(): Returns a stdClass object in the shape of the settings schema, similar to the rest of the json schema objects. To force the correct structure and return the expected stdClass, associative arrays should be cast to objects, e.g.
return (object) [
'title' => 'Example Agency Plugin',
'description' => 'An example plugin used in documenting DOI registration agency plugins',
'type' => 'object',
// Any required field should have their string keys added here'required' => ['requiredTestSetting'],
'properties' => (object) [
'testSetting' => (object) [
'type': 'string',
// Optional params must have nullable validation, otherwise validation checks will require a value'validation' = ['nullable']
],
'requiredTestSetting' => (object) [
'type': 'string',
],
],
]
getFields(): Returns an array of form field classes to be injected in the DOI settings UI, e.g.
return [
newFieldHTML('preamble', [
'label' => __('label.locale.key.here'),
'description' => "<p>Example description/instruction text in HTML here</p>",
]),
newFieldText('testSetting', [
'label' => __('label.locale.key.here'),
'description' => __('description.locale.key.here'),
'value' => $this->agencyPlugin->getSetting($context->getId(), 'testSetting')
]),
]
addValidationChecks(): Any additional checks to be added to the \Illuminate\Validation\Validator instance can be added here, e.g.
protectedfunctionaddValidationChecks(Validator &validator, $props): void
{
$validator->after(function (Validator$validator) use ($props) {
// Add validation checks and errors here
});
}
Export Plugin
This guide will primarily focus on the difference between existing DOI registration agency export plugins and the new architecture. How the actual XML is created and deposited remains largely unchanged, but some additional parameters and modifications have been made.
The existing export plugin should be included alongside (or a new one should be created). The management of interactions between the system and the registration agency plugin are managed through the generic plugin, but the XML creation and depositing are still handled via inherited/slightly modified methods in the export plugin.
Main plugin and settings delegation
Settings have been delegated to the main plugin, so export plugin methods that deal with settings are passed up to the main plugin. We therefore need access to the main plugin within the export plugin, e.g.
and further proxy the settings up to the main plugin, e.g.
/** Proxy to main plugin class's `getSetting` method */publicfunctiongetSetting($contextId, $name)
{
return$this->agencyPlugin->getSetting($contextId, $name);
}
exportAndDeposit()
This is the pre-existing method for handling exporting and depositing. There is a change in function signature to include a string reference for a response message, $responseMessage, to be passed back up to the API and UI.
This is also largely unchanged, but the base method, PubObjectsExportPlugin::exportXML() includes an optional final parameter, array &$exportErrors that should be included when calling exportXML(). If an array is not passed in, PubObjectsExportPlugin::exportXML() will attempt to directly return HTML rather than letting the API & UI framework handle it.
depositXML()
The returned array of errors is passed up to the array reference in exportAndDeposit() and further up through the main plugins export functions and to the API. Status updates should be handled according to the new conventions (see below) and any custom status information (including error or registration messages) should be handled here.
exportAsDownload()
This function should create the XML, save it as a temporary file, and return the temporary file ID, which will be used from the frontend to initiate the file download for the user. A simple example of this looks like:
The temporary file ID gets passed back up to the main plugin's export function, and in turn back up to the API and UI.
updateDepositStatus()
Should update the status to one of Doi::STATUS_* constants for each individual DOI associated with an object, e.g. if a submission has a publication DOI and a galley DOI, both should be updated with the new status.
If the new status is Doi::STATUS_REGISTERED, the registration agency name should be associated with the DOI as well. This is used to differentiate items manually marked registered and those deposited with a registration agency. For example:
foreach ($doiIdsas$doiId) {
$doi = Repo::doi()->get($doiId);
// Any other custom items added to the DOI schema by the main plugin can be stored here$editParams = ['status' => $status];
if ($status === Doi::STATUS_REGISTERED) {
$editParams['registrationAgency'] = $this->getName();
}
Repo::doi()->edit($doi, $editParams);
]
}
markedRegistered()
This method existed previously and its default behaviour looks for a single 'doiId' on the object. If you need to get all doiIds from e.g. a submission, you can override the default behaviour. E.g. in OJS:
publicfunctionmarkRegistered($context, $objects)
{
foreach ($objectsas$object) {
// Get all DOIs for each object// Check if submission or issueif ($objectinstanceof Submission) {
$doiIds = Repo::doi()->getDoisForSubmission($object->getId());
} else {
$doiIds = Repo::doi()->getDoisForIssue($object->getId, true);
}
foreach ($doiIdsas$doiId) {
Repo::doi()->markRegistered($doiId);
}
}
}
Automatic deposit
Automatic depositing is now handled at the application level and all references to it should be removed from the registration agency plugin. Users can enable this from the DOI settings menu.
The text was updated successfully, but these errors were encountered:
@bozana, here is the draft I was able to put together of documentation for registration agency plugins. I wasn't sure where best to put it and haven't had time to revise it in detail, but thought I'd include it here along with a more general issue to add it to the docs hub eventually. This covers working with the registration agency plugins specifically and assumes familiarity with DOIs in 3.4 in general.
The way DOIs work in OJS/OMP/OPS in general was massively overhauled in 3.4, and the way registration agency plugins are treated and interact with the rest of the application as it relates to DOIs has also significantly changed from 3.3. Detailed documentation on what's new, what's needed, and why will be necessary for new developers to understand how DOIs work within the registration agency plugin ecosystem and to be able to write new registration agency plugins.
A draft of all the details related to changes/requirements for registration agency plugins can be found below. 👇
DOI Registration Agency Plugins in 3.4
The following outlines the major architectural changes to how DOIs work with plugins in OJS/OMP/OPS 3.4 and the elements necessary to create a registration agency plugin for 3.4. A plugin that interacts with the DOI functionality is now referred to as a "registration agency plugin" or agency plugin for short.
Implementation Requirements
When creating a new registration agency plugin, there are two different aspects to consider: 1) the functionality that is enforced via code (e.g. required interfaces, inherited methods, etc.) and 2) functionality that is not enforced via code (e.g. functions/hooks that are dictated by convention and won't raise an error in your IDE).
Generic plugin implementing
IDoiRegistrationAgency
detailsThe main plugin must be a
GenericPlugin
and implement theIDoiRegistrationAgency
interfacesetEnabled()
Base implementation defined in
LazyLoadPlugin::setEnabled()
A registration agency plugin can be set as the configured agency plugin at the context level. When the plugin is disabled, if the plugin is currently set as the configured agency plugin, it should be removed, e.g.
exportSubmission()
The export methods are enforced by
IDoiRegistrationAgency
but the shape of the array returned is not. It should return array with the following shape:The actual exporting logic is handled via the export plugin and this method returns results to the API. The function should look something like:
depositSubmission()
The deposit methods are enforced by
IDORegistrationAgency
but the shape of the array returned is not. It should return an array with the following shape:The actual depositing logic is handled via the export plugin and this method returns results to the API. The function should look something like:
addAsRegistrationAgencyOption()
Enforced by
IDoiRegistrationAgency
. Should do the following:isPluginConfigured()
Enforced by
IDoiRegistrationAgency
. Any agency-specific requirements for the plugin can be checked here. Will prevent exporting/depositing if the plugin is not correctly configured.The following snippet can get the required settings from the plugin setting to include as part of the configuration check.
getErrorMessageKey()
&getRegisteredMessageKey()
Enforced by
IDoiRegistrationAgency
.Should return null if not used. If a key is defined, registration or error messages can be saved/associated with individual DOI submissions. If used, the items will need to be added to the DOI schema via the
Schema::get::doi
hook as well as managed throughout the DOI registration lifecycle e.g. removing error messages when successfully deposited, marked registered, etc. Most of the time this should happen in-place when the status is set, except for the DOI being marked registered. TheDoi::markRegistered
hook should be used in this case to modify the params to be saved (see hooks and plugin initialization below).getAllowedDoiTypes()
Enforced by
IDoiRegistrationAgency
. Should return an array of DOI types that are allowed to be registered with this registration agency. E.g.Plugin Initialization and Hooks
Plugin initialization (registration of hooks, etc) should be abstracted out to a private
pluginInitialization()
function that can be called from the plugin'sregister()
function,getExportPlugin()
function (see below), or when attempting to get the export plugin via a CLI operation where plugin registration doesn't happen, e.g.pluginInitialization()
should instantiate the export plugin, add it to the plugin registry, and add any hook callbacks.Required hooks:
DoiSettingsForm::setEnabledRegistrationAgencies
: Callback should beaddAsRegistrationAgency()
method fromIDoiRegistrationAgency
DoiSetupSettingsForm::getObjectTypes
: Which DOI types can be assigned to which plugins are tracked by the settings form and need to be added in the expected way. The callback should look as follows:DoiListPanel::setConfig
: Adds display name in DoiListPanel for agency. The call back should look as follows:Optional hooks:
Context::validate
: Can be used to enforce validation rule to restrict the types of DOIs that can be registered with this agency. The system architecture by default assumes all types are allowed and any restrictions must be specified. Example from the Crossref plugin:Schema::get::doi
: This can be used to add any additional data to be stored alongside DOIs. This can include any agency-specific data, or registration, error messages, e.g.Doi::markRegistered
: If any registration, error, or any other custom messages should be removed when a DOI is marked as registered, that data should be added here, e.g.The param names must be the same as those added to the schema.
Plugin settings,
getSettingsObject()
, andRegistrationAgencySettings
Registration agency plugin settings are integrated with the rest of the DOI settings/options rather than being managed through the plugin settings directly. This is managed by an agency-specific settings class that
getSetingsObject()
should return, e.g.where
AgencySettings
is the plugin-specific class that inherits fromRegistrationAgencySettings
.RegistrationAgencySettings
manages much of the logic for creating the settings directly, but three abstract methods must be overridden in the child class:getSchema()
: Returns astdClass
object in the shape of the settings schema, similar to the rest of the json schema objects. To force the correct structure and return the expectedstdClass
, associative arrays should be cast to objects, e.g.getFields()
: Returns an array of form field classes to be injected in the DOI settings UI, e.g.addValidationChecks()
: Any additional checks to be added to the\Illuminate\Validation\Validator
instance can be added here, e.g.Export Plugin
This guide will primarily focus on the difference between existing DOI registration agency export plugins and the new architecture. How the actual XML is created and deposited remains largely unchanged, but some additional parameters and modifications have been made.
The existing export plugin should be included alongside (or a new one should be created). The management of interactions between the system and the registration agency plugin are managed through the generic plugin, but the XML creation and depositing are still handled via inherited/slightly modified methods in the export plugin.
Main plugin and settings delegation
Settings have been delegated to the main plugin, so export plugin methods that deal with settings are passed up to the main plugin. We therefore need access to the main plugin within the export plugin, e.g.
and further proxy the settings up to the main plugin, e.g.
exportAndDeposit()
This is the pre-existing method for handling exporting and depositing. There is a change in function signature to include a string reference for a response message,
$responseMessage
, to be passed back up to the API and UI.exportXML()
This is also largely unchanged, but the base method,
PubObjectsExportPlugin::exportXML()
includes an optional final parameter,array &$exportErrors
that should be included when callingexportXML()
. If an array is not passed in,PubObjectsExportPlugin::exportXML()
will attempt to directly return HTML rather than letting the API & UI framework handle it.depositXML()
The returned array of errors is passed up to the array reference in
exportAndDeposit()
and further up through the main plugins export functions and to the API. Status updates should be handled according to the new conventions (see below) and any custom status information (including error or registration messages) should be handled here.exportAsDownload()
This function should create the XML, save it as a temporary file, and return the temporary file ID, which will be used from the frontend to initiate the file download for the user. A simple example of this looks like:
The temporary file ID gets passed back up to the main plugin's export function, and in turn back up to the API and UI.
updateDepositStatus()
Should update the status to one of
Doi::STATUS_*
constants for each individual DOI associated with an object, e.g. if a submission has a publication DOI and a galley DOI, both should be updated with the new status.If the new status is
Doi::STATUS_REGISTERED
, the registration agency name should be associated with the DOI as well. This is used to differentiate items manually marked registered and those deposited with a registration agency. For example:markedRegistered()
This method existed previously and its default behaviour looks for a single
'doiId'
on the object. If you need to get alldoiId
s from e.g. a submission, you can override the default behaviour. E.g. in OJS:Automatic deposit
Automatic depositing is now handled at the application level and all references to it should be removed from the registration agency plugin. Users can enable this from the DOI settings menu.
The text was updated successfully, but these errors were encountered: