Open Journal Systems  3.3.0
URNPubIdPlugin.inc.php
1 <?php
2 
17 import('classes.plugins.PubIdPlugin');
18 
19 class URNPubIdPlugin extends PubIdPlugin {
20 
24  public function register($category, $path, $mainContextId = null) {
25  $success = parent::register($category, $path, $mainContextId);
26  if (!Config::getVar('general', 'installed') || defined('RUNNING_UPGRADE')) return $success;
27  if ($success && $this->getEnabled($mainContextId)) {
28  HookRegistry::register('Publication::getProperties::summaryProperties', array($this, 'modifyObjectProperties'));
29  HookRegistry::register('Publication::getProperties::fullProperties', array($this, 'modifyObjectProperties'));
30  HookRegistry::register('Publication::getProperties::values', array($this, 'modifyObjectPropertyValues'));
31  HookRegistry::register('Publication::validate', array($this, 'validatePublicationUrn'));
32  HookRegistry::register('Galley::getProperties::summaryProperties', array($this, 'modifyObjectProperties'));
33  HookRegistry::register('Galley::getProperties::fullProperties', array($this, 'modifyObjectProperties'));
34  HookRegistry::register('Galley::getProperties::values', array($this, 'modifyObjectPropertyValues'));
35  HookRegistry::register('Issue::getProperties::summaryProperties', array($this, 'modifyObjectProperties'));
36  HookRegistry::register('Issue::getProperties::fullProperties', array($this, 'modifyObjectProperties'));
37  HookRegistry::register('Issue::getProperties::values', array($this, 'modifyObjectPropertyValues'));
38  HookRegistry::register('Form::config::before', array($this, 'addPublicationFormFields'));
39  HookRegistry::register('Form::config::before', array($this, 'addPublishFormNotice'));
40  HookRegistry::register('TemplateManager::display', array($this, 'loadUrnFieldComponent'));
41  }
42  return $success;
43  }
44 
45  //
46  // Implement template methods from Plugin.
47  //
51  function getDisplayName() {
52  return __('plugins.pubIds.urn.displayName');
53  }
54 
58  function getDescription() {
59  return __('plugins.pubIds.urn.description');
60  }
61 
62 
63  //
64  // Implement template methods from PubIdPlugin.
65  //
69  function constructPubId($pubIdPrefix, $pubIdSuffix, $contextId) {
70  $urn = $pubIdPrefix . $pubIdSuffix;
71  $suffixFieldName = $this->getSuffixFieldName();
72  $suffixGenerationStrategy = $this->getSetting($contextId, $suffixFieldName);
73  // checkNo is already calculated for custom suffixes
74  if ($suffixGenerationStrategy != 'customId' && $this->getSetting($contextId, 'urnCheckNo')) {
75  $urn .= $this->_calculateCheckNo($urn);
76  }
77  return $urn;
78  }
79 
83  function getPubIdType() {
84  return 'other::urn';
85  }
86 
90  function getPubIdDisplayType() {
91  return 'URN';
92  }
93 
97  function getPubIdFullName() {
98  return 'Uniform Resource Name';
99  }
100 
104  function getResolvingURL($contextId, $pubId) {
105  $resolverURL = $this->getSetting($contextId, 'urnResolver');
106  return $resolverURL . $pubId;
107  }
108 
112  function getPubIdMetadataFile() {
113  return $this->getTemplateResource('urnSuffixEdit.tpl');
114  }
115 
119  function addJavaScript($request, $templateMgr) {
120  $templateMgr->addJavaScript(
121  'urnCheckNo',
122  $request->getBaseUrl() . DIRECTORY_SEPARATOR . $this->getPluginPath() . DIRECTORY_SEPARATOR . 'js' . DIRECTORY_SEPARATOR . 'checkNumber.js',
123  array(
124  'inline' => false,
125  'contexts' => ['publicIdentifiersForm', 'backend'],
126  )
127  );
128  }
129 
133  function getPubIdAssignFile() {
134  return $this->getTemplateResource('urnAssign.tpl');
135  }
136 
140  function instantiateSettingsForm($contextId) {
141  $this->import('classes.form.URNSettingsForm');
142  return new URNSettingsForm($this, $contextId);
143  }
144 
148  function getFormFieldNames() {
149  return array('urnSuffix');
150  }
151 
156  return 'assignURN';
157  }
158 
162  function getPrefixFieldName() {
163  return 'urnPrefix';
164  }
165 
169  function getSuffixFieldName() {
170  return 'urnSuffix';
171  }
172 
176  function getLinkActions($pubObject) {
177  $linkActions = array();
178  import('lib.pkp.classes.linkAction.request.RemoteActionConfirmationModal');
179  $request = Application::get()->getRequest();
180  $userVars = $request->getUserVars();
181  $userVars['pubIdPlugIn'] = get_class($this);
182  // Clear object pub id
183  $linkActions['clearPubIdLinkActionURN'] = new LinkAction(
184  'clearPubId',
186  $request->getSession(),
187  __('plugins.pubIds.urn.editor.clearObjectsURN.confirm'),
188  __('common.delete'),
189  $request->url(null, null, 'clearPubId', null, $userVars),
190  'modal_delete'
191  ),
192  __('plugins.pubIds.urn.editor.clearObjectsURN'),
193  'delete',
194  __('plugins.pubIds.urn.editor.clearObjectsURN')
195  );
196 
197  if (is_a($pubObject, 'Issue')) {
198  // Clear issue objects pub ids
199  $linkActions['clearIssueObjectsPubIdsLinkActionURN'] = new LinkAction(
200  'clearObjectsPubIds',
202  $request->getSession(),
203  __('plugins.pubIds.urn.editor.clearIssueObjectsURN.confirm'),
204  __('common.delete'),
205  $request->url(null, null, 'clearIssueObjectsPubIds', null, $userVars),
206  'modal_delete'
207  ),
208  __('plugins.pubIds.urn.editor.clearIssueObjectsURN'),
209  'delete',
210  __('plugins.pubIds.urn.editor.clearIssueObjectsURN')
211  );
212  }
213 
214  return $linkActions;
215  }
216 
221  return array(
222  'Issue' => 'urnIssueSuffixPattern',
223  'Submission' => 'urnPublicationSuffixPattern',
224  'Representation' => 'urnRepresentationSuffixPattern',
225  );
226  }
227 
231  function getDAOFieldNames() {
232  return array('pub-id::other::urn');
233  }
234 
238  function isObjectTypeEnabled($pubObjectType, $contextId) {
239  return (boolean) $this->getSetting($contextId, "enable${pubObjectType}URN");
240  }
241 
245  function getNotUniqueErrorMsg() {
246  return __('plugins.pubIds.urn.editor.urnSuffixCustomIdentifierNotUnique');
247  }
248 
262  public function modifyObjectProperties($hookName, $args) {
263  $props =& $args[0];
264 
265  $props[] = 'pub-id::other::urn';
266  }
267 
281  public function modifyObjectPropertyValues($hookName, $args) {
282  $values =& $args[0];
283  $object = $args[1];
284  $props = $args[2];
285 
286  // URNs are not supported for IssueGalleys
287  if (get_class($object) === 'IssueGalley') {
288  return;
289  }
290 
291  // URNs are already added to property values for Publications and Galleys
292  if (get_class($object) === 'Publication' || get_class($object) === 'ArticleGalley') {
293  return;
294  }
295 
296  if (in_array('pub-id::other::urn', $props)) {
297  $pubId = $this->getPubId($object);
298  $values['pub-id::other::urn'] = $pubId ? $pubId : null;
299  }
300  }
301 
308  public function validatePublicationUrn($hookName, $args) {
309  $errors =& $args[0];
310  $action = $args[1];
311  $props =& $args[2];
312 
313  if (empty($props['pub-id::other::urn'])) {
314  return;
315  }
316 
317  if ($action === VALIDATE_ACTION_ADD) {
318  $submission = Services::get('submission')->get($props['submissionId']);
319  } else {
320  $publication = Services::get('publication')->get($props['id']);
321  $submission = Services::get('submission')->get($publication->getData('submissionId'));
322  }
323 
324  $contextId = $submission->getData('contextId');
325  $urnPrefix = $this->getSetting($contextId, 'urnPrefix');
326 
327  $urnErrors = [];
328  if (strpos($props['pub-id::other::urn'], $urnPrefix) !== 0) {
329  $urnErrors[] = __('plugins.pubIds.urn.editor.missingPrefix', ['urnPrefix' => $urnPrefix]);
330  }
331  if (!$this->checkDuplicate($props['pub-id::other::urn'], 'Publication', $submission->getId(), $contextId)) {
332  $urnErrors[] = $this->getNotUniqueErrorMsg();
333  }
334  if (!empty($urnErrors)) {
335  $errors['pub-id::other::urn'] = $urnErrors;
336  }
337  }
338 
345  public function addPublicationFormFields($hookName, $form) {
346 
347  if ($form->id !== 'publicationIdentifiers') {
348  return;
349  }
350 
351  if (!$this->getSetting($form->submissionContext->getId(), 'enablePublicationURN')) {
352  return;
353  }
354 
355  $prefix = $this->getSetting($form->submissionContext->getId(), 'urnPrefix');
356 
357  $suffixType = $this->getSetting($form->submissionContext->getId(), 'urnSuffix');
358  $pattern = '';
359  if ($suffixType === 'default') {
360  $pattern = '%j.v%vi%i.%a';
361  } elseif ($suffixType === 'pattern') {
362  $pattern = $this->getSetting($form->submissionContext->getId(), 'urnPublicationSuffixPattern');
363  }
364 
365  // If a pattern exists, use a DOI-like field to generate the URN
366  if ($pattern) {
367  $fieldData = [
368  'label' => __('plugins.pubIds.urn.displayName'),
369  'value' => $form->publication->getData('pub-id::other::urn'),
370  'prefix' => $prefix,
371  'pattern' => $pattern,
372  'contextInitials' => $form->submissionContext->getData('acronym', $form->submissionContext->getData('primaryLocale')) ?? '',
373  'submissionId' => $form->publication->getData('submissionId'),
374  'assignId' => __('plugins.pubIds.urn.editor.urn.assignUrn'),
375  'clearId' => __('plugins.pubIds.urn.editor.clearObjectsURN'),
376  ];
377  if ($form->publication->getData('pub-id::publisher-id')) {
378  $fieldData['publisherId'] = $form->publication->getData('pub-id::publisher-id');
379  }
380  if ($form->publication->getData('pages')) {
381  $fieldData['pages'] = $form->publication->getData('pages');
382  }
383  if ($form->publication->getData('issueId')) {
384  $issue = Services::get('issue')->get($form->publication->getData('issueId'));
385  if ($issue) {
386  $fieldData['issueNumber'] = $issue->getNumber() ?? '';
387  $fieldData['issueVolume'] = $issue->getVolume() ?? '';
388  $fieldData['year'] = $issue->getYear() ?? '';
389  }
390  }
391  if ($suffixType === 'default') {
392  $fieldData['missingPartsLabel'] = __('plugins.pubIds.urn.editor.missingIssue');
393  } else {
394  $fieldData['missingPartsLabel'] = __('plugins.pubIds.urn.editor.missingParts');
395  }
396  $form->addField(new \PKP\components\forms\FieldPubId('pub-id::other::urn', $fieldData));
397 
398  // Otherwise add a field for manual entry that includes a button to generate
399  // the check number
400  } else {
401  // Load the checkNumber.js file that is required for this field
403 
404  $this->import('classes.form.FieldUrn');
405  $form->addField(new \Plugins\Generic\URN\FieldUrn('pub-id::other::urn', [
406  'label' => __('plugins.pubIds.urn.displayName'),
407  'description' => __('plugins.pubIds.urn.editor.urn.description', ['prefix' => $prefix]),
408  'value' => $form->publication->getData('pub-id::other::urn'),
409  ]));
410  }
411  }
412 
419  public function addPublishFormNotice($hookName, $form) {
420 
421  if ($form->id !== 'publish' || !empty($form->errors)) {
422  return;
423  }
424 
425  $submission = Services::get('submission')->get($form->publication->getData('submissionId'));
426  $publicationUrnEnabled = $this->getSetting($submission->getData('contextId'), 'enablePublicationURN');
427  $galleyUrnEnabled = $this->getSetting($submission->getData('contextId'), 'enableRepresentationURN');
428  $warningIconHtml = '<span class="fa fa-exclamation-triangle pkpIcon--inline"></span>';
429 
430  if (!$publicationUrnEnabled && !$galleyUrnEnabled) {
431  return;
432 
433  // Use a simplified view when only assigning to the publication
434  } else if (!$galleyUrnEnabled) {
435  if ($form->publication->getData('pub-id::other::urn')) {
436  $msg = __('plugins.pubIds.urn.editor.preview.publication', ['urn' => $form->publication->getData('pub-id::other::urn')]);
437  } else {
438  $msg = '<div class="pkpNotification pkpNotification--warning">' . $warningIconHtml . __('plugins.pubIds.urn.editor.preview.publication.none') . '</div>';
439  }
440  $form->addField(new \PKP\components\forms\FieldHTML('urn', [
441  'description' => $msg,
442  'groupId' => 'default',
443  ]));
444  return;
445 
446  // Show a table if more than one URN is going to be created
447  } else {
448  $urnTableRows = [];
449  if ($publicationUrnEnabled) {
450  if ($form->publication->getData('pub-id::other::urn')) {
451  $urnTableRows[] = [$form->publication->getData('pub-id::other::urn'), 'Publication'];
452  } else {
453  $urnTableRows[] = [$warningIconHtml . __('submission.status.unassigned'), 'Publication'];
454  }
455  }
456  if ($galleyUrnEnabled) {
457  foreach ((array) $form->publication->getData('galleys') as $galley) {
458  if ($galley->getStoredPubId('other::urn')) {
459  $urnTableRows[] = [$galley->getStoredPubId('other::urn'), __('plugins.pubIds.urn.editor.preview.galleys', ['galleyLabel' => $galley->getGalleyLabel()])];
460  } else {
461  $urnTableRows[] = [$warningIconHtml . __('submission.status.unassigned'),__('plugins.pubIds.urn.editor.preview.galleys', ['galleyLabel' => $galley->getGalleyLabel()])];
462  }
463  }
464  }
465  if (!empty($urnTableRows)) {
466  $table = '<table class="pkpTable"><thead><tr>' .
467  '<th>' . __('plugins.pubIds.urn.displayName') . '</th>' .
468  '<th>' . __('plugins.pubIds.urn.editor.preview.objects') . '</th>' .
469  '</tr></thead><tbody>';
470  foreach ($urnTableRows as $urnTableRow) {
471  $table .= '<tr><td>' . $urnTableRow[0] . '</td><td>' . $urnTableRow[1] . '</td></tr>';
472  }
473  $table .= '</tbody></table>';
474  }
475  $form->addField(new \PKP\components\forms\FieldHTML('urn', [
476  'description' => $table,
477  'groupId' => 'default',
478  ]));
479  }
480  }
481 
488  public function loadUrnFieldComponent($hookName, $args) {
489  $templateMgr = $args[0];
490  $template = $args[1];
491 
492  if ($template !== 'workflow/workflow.tpl') {
493  return;
494  }
495 
496  $templateMgr->addJavaScript(
497  'urn-field-component',
498  Application::get()->getRequest()->getBaseUrl() . '/' . $this->getPluginPath() . '/js/FieldUrn.js',
499  [
500  'contexts' => 'backend',
501  'priority' => STYLE_SEQUENCE_LAST,
502  ]
503  );
504 
505  $templateMgr->addStyleSheet(
506  'urn-field-component',
507  '
508  .pkpFormField--urn__input {
509  display: inline-block;
510  }
511 
512  .pkpFormField--urn__button {
513  margin-left: 0.25rem;
514  height: 2.5rem; // Match input height
515  }
516  ',
517  [
518  'contexts' => 'backend',
519  'inline' => true,
520  'priority' => STYLE_SEQUENCE_LAST,
521  ]
522  );
523  }
524 
525  //
526  // Private helper methods
527  //
537  function _calculateCheckNo($urn) {
538  $urnLower = strtolower_codesafe($urn);
539 
540  $conversionTable = array('9' => '41', '8' => '9', '7' => '8', '6' => '7', '5' => '6', '4' => '5', '3' => '4', '2' => '3', '1' => '2', '0' => '1', 'a' => '18', 'b' => '14', 'c' => '19', 'd' => '15', 'e' => '16', 'f' => '21', 'g' => '22', 'h' => '23', 'i' => '24', 'j' => '25', 'k' => '42', 'l' => '26', 'm' => '27', 'n' => '13', 'o' => '28', 'p' => '29', 'q' => '31', 'r' => '12', 's' => '32', 't' => '33', 'u' => '11', 'v' => '34', 'w' => '35', 'x' => '36', 'y' => '37', 'z' => '38', '-' => '39', ':' => '17', '_' => '43', '/' => '45', '.' => '47', '+' => '49');
541 
542  $newURN = '';
543  for ($i = 0; $i < strlen($urnLower); $i++) {
544  $char = $urnLower[$i];
545  $newURN .= $conversionTable[$char];
546  }
547  $sum = 0;
548  for ($j = 1; $j <= strlen($newURN); $j++) {
549  $sum = $sum + ($newURN[$j-1] * $j);
550  }
551 
552  $lastNumber = $newURN[strlen($newURN)-1];
553  $quot = $sum / $lastNumber;
554  $quotRound = floor($quot);
555  $quotString = (string)$quotRound;
556 
557  return $quotString[strlen($quotString)-1];
558  }
559 }
560 
561 
URNSettingsForm
Form for journal managers to setup URN plugin.
Definition: URNSettingsForm.inc.php:19
RemoteActionConfirmationModal
Class defining a simple confirmation modal with a remote action and ok/cancel buttons.
Definition: RemoteActionConfirmationModal.inc.php:18
PKP
FieldPubId
A field for generating a pub id, like a DOI.
URNPubIdPlugin\addJavaScript
addJavaScript($request, $templateMgr)
Definition: URNPubIdPlugin.inc.php:119
Plugin\getRequest
& getRequest()
Definition: Plugin.inc.php:828
URNPubIdPlugin\getPubIdMetadataFile
getPubIdMetadataFile()
Definition: URNPubIdPlugin.inc.php:112
FieldUrn
A field for entering a URN and then having the check number generated.
URNPubIdPlugin\getNotUniqueErrorMsg
getNotUniqueErrorMsg()
Definition: URNPubIdPlugin.inc.php:245
PubIdPlugin
Public identifiers plugins common functions.
Definition: PubIdPlugin.inc.php:18
URNPubIdPlugin\modifyObjectPropertyValues
modifyObjectPropertyValues($hookName, $args)
Definition: URNPubIdPlugin.inc.php:281
URNPubIdPlugin\getPrefixFieldName
getPrefixFieldName()
Definition: URNPubIdPlugin.inc.php:162
URNPubIdPlugin
URN plugin class.
Definition: URNPubIdPlugin.inc.php:19
PubIdPlugin\checkDuplicate
checkDuplicate($pubId, $pubObjectType, $excludeId, $contextId)
Definition: PubIdPlugin.inc.php:104
URNPubIdPlugin\loadUrnFieldComponent
loadUrnFieldComponent($hookName, $args)
Definition: URNPubIdPlugin.inc.php:488
URNPubIdPlugin\getPubIdDisplayType
getPubIdDisplayType()
Definition: URNPubIdPlugin.inc.php:90
URNPubIdPlugin\getSuffixFieldName
getSuffixFieldName()
Definition: URNPubIdPlugin.inc.php:169
Plugins
URNPubIdPlugin\getDAOFieldNames
getDAOFieldNames()
Definition: URNPubIdPlugin.inc.php:231
URNPubIdPlugin\getPubIdAssignFile
getPubIdAssignFile()
Definition: URNPubIdPlugin.inc.php:133
Plugin\getEnabled
getEnabled()
Definition: Plugin.inc.php:868
Plugin\getSetting
getSetting($contextId, $name)
Definition: Plugin.inc.php:473
Config\getVar
static getVar($section, $key, $default=null)
Definition: Config.inc.php:35
URNPubIdPlugin\getFormFieldNames
getFormFieldNames()
Definition: URNPubIdPlugin.inc.php:148
LinkAction
Base class defining an action that can be performed by the user in the user interface.
Definition: LinkAction.inc.php:22
URNPubIdPlugin\instantiateSettingsForm
instantiateSettingsForm($contextId)
Definition: URNPubIdPlugin.inc.php:140
PubIdPlugin\getPubId
getPubId($pubObject)
Definition: PubIdPlugin.inc.php:121
PKPTemplateManager\getManager
static & getManager($request=null)
Definition: PKPTemplateManager.inc.php:1239
URNPubIdPlugin\getResolvingURL
getResolvingURL($contextId, $pubId)
Definition: URNPubIdPlugin.inc.php:104
URNPubIdPlugin\_calculateCheckNo
_calculateCheckNo($urn)
Definition: URNPubIdPlugin.inc.php:537
URNPubIdPlugin\addPublicationFormFields
addPublicationFormFields($hookName, $form)
Definition: URNPubIdPlugin.inc.php:345
URNPubIdPlugin\getDisplayName
getDisplayName()
Definition: URNPubIdPlugin.inc.php:51
Plugin\getTemplateResource
getTemplateResource($template=null, $inCore=false)
Definition: Plugin.inc.php:349
strtolower_codesafe
strtolower_codesafe($str)
Definition: functions.inc.php:280
Plugin\getPluginPath
getPluginPath()
Definition: Plugin.inc.php:330
URNPubIdPlugin\isObjectTypeEnabled
isObjectTypeEnabled($pubObjectType, $contextId)
Definition: URNPubIdPlugin.inc.php:238
URNPubIdPlugin\getPubIdType
getPubIdType()
Definition: URNPubIdPlugin.inc.php:83
Plugin\$request
$request
Definition: Plugin.inc.php:68
HookRegistry\register
static register($hookName, $callback, $hookSequence=HOOK_SEQUENCE_NORMAL)
Definition: HookRegistry.inc.php:70
URNPubIdPlugin\getSuffixPatternsFieldNames
getSuffixPatternsFieldNames()
Definition: URNPubIdPlugin.inc.php:220
PKPApplication\get
static get()
Definition: PKPApplication.inc.php:235
URNPubIdPlugin\getPubIdFullName
getPubIdFullName()
Definition: URNPubIdPlugin.inc.php:97
FieldHTML
A component for inserting HTML into a form, when you don't need any input fields or values stored.
URNPubIdPlugin\getDescription
getDescription()
Definition: URNPubIdPlugin.inc.php:58
URNPubIdPlugin\validatePublicationUrn
validatePublicationUrn($hookName, $args)
Definition: URNPubIdPlugin.inc.php:308
URNPubIdPlugin\constructPubId
constructPubId($pubIdPrefix, $pubIdSuffix, $contextId)
Definition: URNPubIdPlugin.inc.php:69
URNPubIdPlugin\getLinkActions
getLinkActions($pubObject)
Definition: URNPubIdPlugin.inc.php:176
URNPubIdPlugin\addPublishFormNotice
addPublishFormNotice($hookName, $form)
Definition: URNPubIdPlugin.inc.php:419
PKPServices\get
static get($service)
Definition: PKPServices.inc.php:49
URNPubIdPlugin\getAssignFormFieldName
getAssignFormFieldName()
Definition: URNPubIdPlugin.inc.php:155
URNPubIdPlugin\modifyObjectProperties
modifyObjectProperties($hookName, $args)
Definition: URNPubIdPlugin.inc.php:262