Open Journal Systems  3.3.0
NativeImportExportPlugin.inc.php
1 <?php
2 
16 import('lib.pkp.classes.plugins.ImportExportPlugin');
17 
19 
23  function register($category, $path, $mainContextId = null) {
24  $success = parent::register($category, $path, $mainContextId);
25  $this->addLocaleData();
26  $this->import('NativeImportExportDeployment');
27  return $success;
28  }
29 
35  function getName() {
36  return 'NativeImportExportPlugin';
37  }
38 
43  function getDisplayName() {
44  return __('plugins.importexport.native.displayName');
45  }
46 
51  function getDescription() {
52  return __('plugins.importexport.native.description');
53  }
54 
59  return 'native';
60  }
61 
67  function display($args, $request) {
68  parent::display($args, $request);
69  $templateMgr = TemplateManager::getManager($request);
70  $context = $request->getContext();
71  switch (array_shift($args)) {
72  case 'index':
73  case '':
74  $apiUrl = $request->getDispatcher()->url($request, ROUTE_API, $context->getPath(), 'submissions');
75  $submissionsListPanel = new \APP\components\listPanels\SubmissionsListPanel(
76  'submissions',
77  __('common.publications'),
78  [
79  'apiUrl' => $apiUrl,
80  'count' => 100,
81  'getParams' => new stdClass(),
82  'lazyLoad' => true,
83  ]
84  );
85  $submissionsConfig = $submissionsListPanel->getConfig();
86  $submissionsConfig['addUrl'] = '';
87  $submissionsConfig['filters'] = array_slice($submissionsConfig['filters'], 1);
88  $templateMgr->setState([
89  'components' => [
90  'submissions' => $submissionsConfig,
91  ],
92  ]);
93  $templateMgr->assign([
94  'pageComponent' => 'ImportExportPage',
95  ]);
96  $templateMgr->display($this->getTemplateResource('index.tpl'));
97  break;
98  case 'uploadImportXML':
99  $user = $request->getUser();
100  import('lib.pkp.classes.file.TemporaryFileManager');
101  $temporaryFileManager = new TemporaryFileManager();
102  $temporaryFile = $temporaryFileManager->handleUpload('uploadedFile', $user->getId());
103  if ($temporaryFile) {
104  $json = new JSONMessage(true);
105  $json->setAdditionalAttributes(array(
106  'temporaryFileId' => $temporaryFile->getId()
107  ));
108  } else {
109  $json = new JSONMessage(false, __('common.uploadFailed'));
110  }
111  header('Content-Type: application/json');
112  return $json->getString();
113  case 'importBounce':
114  $json = new JSONMessage(true);
115  $json->setEvent('addTab', array(
116  'title' => __('plugins.importexport.native.results'),
117  'url' => $request->url(null, null, null, array('plugin', $this->getName(), 'import'), array('temporaryFileId' => $request->getUserVar('temporaryFileId'))),
118  ));
119  header('Content-Type: application/json');
120  return $json->getString();
121  case 'import':
122  AppLocale::requireComponents(LOCALE_COMPONENT_PKP_SUBMISSION);
123  $temporaryFileId = $request->getUserVar('temporaryFileId');
124  $temporaryFileDao = DAORegistry::getDAO('TemporaryFileDAO'); /* @var $temporaryFileDao TemporaryFileDAO */
125  $user = $request->getUser();
126  $temporaryFile = $temporaryFileDao->getTemporaryFile($temporaryFileId, $user->getId());
127  if (!$temporaryFile) {
128  $json = new JSONMessage(true, __('plugins.inportexport.native.uploadFile'));
129  header('Content-Type: application/json');
130  return $json->getString();
131  }
132  $temporaryFilePath = $temporaryFile->getFilePath();
133 
134  $filter = 'native-xml=>issue';
135  // is this articles import:
136  $xmlString = file_get_contents($temporaryFilePath);
137  $document = new DOMDocument();
138  $document->loadXml($xmlString);
139  if (in_array($document->documentElement->tagName, array('article', 'articles'))) {
140  $filter = 'native-xml=>article';
141  }
142 
143  $deployment = new NativeImportExportDeployment($context, $user);
144 
145  libxml_use_internal_errors(true);
146  $content = $this->importSubmissions(file_get_contents($temporaryFilePath), $filter, $deployment);
147  $templateMgr->assign('content', $content);
148  $validationErrors = array_filter(libxml_get_errors(), function($a) {
149  return $a->level == LIBXML_ERR_ERROR || $a->level == LIBXML_ERR_FATAL;
150  });
151  $templateMgr->assign('validationErrors', $validationErrors);
152  libxml_clear_errors();
153 
154  // Are there any import warnings? Display them.
155  $warningTypes = array(
156  ASSOC_TYPE_ISSUE => 'issuesWarnings',
157  ASSOC_TYPE_SUBMISSION => 'submissionsWarnings',
158  ASSOC_TYPE_SECTION => 'sectionWarnings',
159  );
160  foreach ($warningTypes as $assocType => $templateVar) {
161  $foundWarnings = $deployment->getProcessedObjectsWarnings($assocType);
162  if (!empty($foundWarnings)) {
163  $templateMgr->assign($templateVar, $foundWarnings);
164  }
165  }
166 
167  // Are there any import errors? Display them.
168  $errorTypes = array(
169  ASSOC_TYPE_ISSUE => 'issuesErrors',
170  ASSOC_TYPE_SUBMISSION => 'submissionsErrors',
171  ASSOC_TYPE_SECTION => 'sectionErrors',
172  );
173  $foundErrors = false;
174  foreach ($errorTypes as $assocType => $templateVar) {
175  $currentErrors = $deployment->getProcessedObjectsErrors($assocType);
176  if (!empty($currentErrors)) {
177  $templateMgr->assign($templateVar, $currentErrors);
178  $foundErrors = true;
179  }
180  }
181  // If there are any data or validataion errors
182  // delete imported objects.
183  if ($foundErrors || !empty($validationErrors)) {
184  // remove all imported issues and sumissions
185  foreach (array_keys($errorTypes) as $assocType) {
186  $deployment->removeImportedObjects($assocType);
187  }
188  }
189  // Display the results
190  $json = new JSONMessage(true, $templateMgr->fetch($this->getTemplateResource('results.tpl')));
191  header('Content-Type: application/json');
192  return $json->getString();
193  case 'exportSubmissions':
194  $exportXml = $this->exportSubmissions(
195  (array) $request->getUserVar('selectedSubmissions'),
196  $request->getContext(),
197  $request->getUser()
198  );
199  import('lib.pkp.classes.file.FileManager');
200  $fileManager = new FileManager();
201  $exportFileName = $this->getExportFileName($this->getExportPath(), 'articles', $context, '.xml');
202  $fileManager->writeFile($exportFileName, $exportXml);
203  $fileManager->downloadByPath($exportFileName);
204  $fileManager->deleteByPath($exportFileName);
205  break;
206  case 'exportIssues':
207  $exportXml = $this->exportIssues(
208  (array) $request->getUserVar('selectedIssues'),
209  $request->getContext(),
210  $request->getUser()
211  );
212  import('lib.pkp.classes.file.FileManager');
213  $fileManager = new FileManager();
214  $exportFileName = $this->getExportFileName($this->getExportPath(), 'issues', $context, '.xml');
215  $fileManager->writeFile($exportFileName, $exportXml);
216  $fileManager->downloadByPath($exportFileName);
217  $fileManager->deleteByPath($exportFileName);
218  break;
219  default:
220  $dispatcher = $request->getDispatcher();
221  $dispatcher->handle404();
222  }
223  }
224 
233  function exportSubmissions($submissionIds, $context, $user, $opts = array()) {
234  $submissionDao = DAORegistry::getDAO('SubmissionDAO'); /* @var $submissionDao SubmissionDAO */
235  $filterDao = DAORegistry::getDAO('FilterDAO'); /* @var $filterDao FilterDAO */
236  $nativeExportFilters = $filterDao->getObjectsByGroup('article=>native-xml');
237  assert(count($nativeExportFilters) == 1); // Assert only a single serialization filter
238  $exportFilter = array_shift($nativeExportFilters);
239  $exportFilter->setDeployment(new NativeImportExportDeployment($context, $user));
240 
241  $submissions = array();
242  foreach ($submissionIds as $submissionId) {
244  $submissionService = Services::get('submission');
245  $submission = $submissionService->get($submissionId);
246 
247  if ($submission) $submissions[] = $submission;
248  }
249 
250  libxml_use_internal_errors(true);
251  $exportFilter->setOpts($opts);
252  $submissionXml = $exportFilter->execute($submissions, true);
253  $xml = $submissionXml->saveXml();
254 
255  $errors = array_filter(libxml_get_errors(), function($a) {
256  return $a->level == LIBXML_ERR_ERROR || $a->level == LIBXML_ERR_FATAL;
257  });
258 
259  if (!empty($errors)) {
260  $this->displayXMLValidationErrors($errors, $xml);
261  }
262 
263  return $xml;
264  }
265 
273  function exportIssues($issueIds, $context, $user, $opts = array()) {
274  $issueDao = DAORegistry::getDAO('IssueDAO'); /* @var $issueDao IssueDAO */
275  $filterDao = DAORegistry::getDAO('FilterDAO'); /* @var $filterDao FilterDAO */
276  $nativeExportFilters = $filterDao->getObjectsByGroup('issue=>native-xml');
277  assert(count($nativeExportFilters) == 1); // Assert only a single serialization filter
278  $exportFilter = array_shift($nativeExportFilters);
279  $exportFilter->setDeployment(new NativeImportExportDeployment($context, $user));
280  $issues = array();
281  foreach ($issueIds as $issueId) {
282  $issue = $issueDao->getById($issueId, $context->getId());
283  if ($issue) $issues[] = $issue;
284  }
285  libxml_use_internal_errors(true);
286  $exportFilter->setOpts($opts);
287  $issueXml = $exportFilter->execute($issues, true);
288  $xml = $issueXml->saveXml();
289  $errors = array_filter(libxml_get_errors(), function($a) {
290  return $a->level == LIBXML_ERR_ERROR || $a->level == LIBXML_ERR_FATAL;
291  });
292  if (!empty($errors)) {
293  $this->displayXMLValidationErrors($errors, $xml);
294  }
295  return $xml;
296  }
297 
305  function importSubmissions($importXml, $filter, $deployment) {
306  $filterDao = DAORegistry::getDAO('FilterDAO'); /* @var $filterDao FilterDAO */
307  $nativeImportFilters = $filterDao->getObjectsByGroup($filter);
308  assert(count($nativeImportFilters) == 1); // Assert only a single unserialization filter
309  $importFilter = array_shift($nativeImportFilters);
310  $importFilter->setDeployment($deployment);
311  return $importFilter->execute($importXml);
312  }
313 
317  function usage($scriptName) {
318  echo __('plugins.importexport.native.cliUsage', array(
319  'scriptName' => $scriptName,
320  'pluginName' => $this->getName()
321  )) . "\n";
322  }
323 
327  function executeCLI($scriptName, &$args) {
328  $opts = $this->parseOpts($args, ['no-embed', 'use-file-urls']);
329  $command = array_shift($args);
330  $xmlFile = array_shift($args);
331  $journalPath = array_shift($args);
332 
333  AppLocale::requireComponents(LOCALE_COMPONENT_APP_MANAGER, LOCALE_COMPONENT_PKP_MANAGER, LOCALE_COMPONENT_PKP_SUBMISSION);
334 
335  $journalDao = DAORegistry::getDAO('JournalDAO'); /* @var $journalDao JournalDAO */
336  $userDao = DAORegistry::getDAO('UserDAO'); /* @var $userDao UserDAO */
337 
338  $journal = $journalDao->getByPath($journalPath);
339 
340  if (!$journal) {
341  if ($journalPath != '') {
342  echo __('plugins.importexport.common.cliError') . "\n";
343  echo __('plugins.importexport.common.error.unknownJournal', array('journalPath' => $journalPath)) . "\n\n";
344  }
345  $this->usage($scriptName);
346  return;
347  }
348 
349  if ($xmlFile && $this->isRelativePath($xmlFile)) {
350  $xmlFile = PWD . '/' . $xmlFile;
351  }
352 
353  switch ($command) {
354  case 'import':
355  $userName = array_shift($args);
356  $user = $userDao->getByUsername($userName);
357 
358  if (!$user) {
359  if ($userName != '') {
360  echo __('plugins.importexport.common.cliError') . "\n";
361  echo __('plugins.importexport.native.error.unknownUser', array('userName' => $userName)) . "\n\n";
362  }
363  $this->usage($scriptName);
364  return;
365  }
366 
367  if (!file_exists($xmlFile)) {
368  echo __('plugins.importexport.common.cliError') . "\n";
369  echo __('plugins.importexport.common.export.error.inputFileNotReadable', array('param' => $xmlFile)) . "\n\n";
370  $this->usage($scriptName);
371  return;
372  }
373 
374  $filter = 'native-xml=>issue';
375  // is this articles import:
376  $xmlString = file_get_contents($xmlFile);
377  $document = new DOMDocument();
378  $document->loadXml($xmlString);
379  if (in_array($document->documentElement->tagName, array('article', 'articles'))) {
380  $filter = 'native-xml=>article';
381  }
382  $deployment = new NativeImportExportDeployment($journal, $user);
383  $deployment->setImportPath(dirname($xmlFile));
384  $content = $this->importSubmissions($xmlString, $filter, $deployment);
385  $validationErrors = array_filter(libxml_get_errors(), function($a) {
386  return $a->level == LIBXML_ERR_ERROR || $a->level == LIBXML_ERR_FATAL;
387  });
388 
389  // Are there any import warnings? Display them.
390  $errorTypes = array(
391  ASSOC_TYPE_ISSUE => 'issue.issue',
392  ASSOC_TYPE_SUBMISSION => 'submission.submission',
393  ASSOC_TYPE_SECTION => 'section.section',
394  );
395  foreach ($errorTypes as $assocType => $localeKey) {
396  $foundWarnings = $deployment->getProcessedObjectsWarnings($assocType);
397  if (!empty($foundWarnings)) {
398  echo __('plugins.importexport.common.warningsEncountered') . "\n";
399  $i = 0;
400  foreach ($foundWarnings as $foundWarningMessages) {
401  if (count($foundWarningMessages) > 0) {
402  echo ++$i . '.' . __($localeKey) . "\n";
403  foreach ($foundWarningMessages as $foundWarningMessage) {
404  echo '- ' . $foundWarningMessage . "\n";
405  }
406  }
407  }
408  }
409  }
410 
411  // Are there any import errors? Display them.
412  $foundErrors = false;
413  foreach ($errorTypes as $assocType => $localeKey) {
414  $currentErrors = $deployment->getProcessedObjectsErrors($assocType);
415  if (!empty($currentErrors)) {
416  echo __('plugins.importexport.common.errorsOccured') . "\n";
417  $i = 0;
418  foreach ($currentErrors as $currentErrorMessages) {
419  if (count($currentErrorMessages) > 0) {
420  echo ++$i . '.' . __($localeKey) . "\n";
421  foreach ($currentErrorMessages as $currentErrorMessage) {
422  echo '- ' . $currentErrorMessage . "\n";
423  }
424  }
425  }
426  $foundErrors = true;
427  }
428  }
429  // If there are any data or validataion errors
430  // delete imported objects.
431  if ($foundErrors || !empty($validationErrors)) {
432  // remove all imported issues and sumissions
433  foreach (array_keys($errorTypes) as $assocType) {
434  $deployment->removeImportedObjects($assocType);
435  }
436  }
437  return;
438  case 'export':
439  $outputDir = dirname($xmlFile);
440  if (!is_writable($outputDir) || (file_exists($xmlFile) && !is_writable($xmlFile))) {
441  echo __('plugins.importexport.common.cliError') . "\n";
442  echo __('plugins.importexport.common.export.error.outputFileNotWritable', array('param' => $xmlFile)) . "\n\n";
443  $this->usage($scriptName);
444  return;
445  }
446  if ($xmlFile != '') switch (array_shift($args)) {
447  case 'article':
448  case 'articles':
449  file_put_contents($xmlFile, $this->exportSubmissions(
450  $args,
451  $journal,
452  null,
453  $opts
454  ));
455  return;
456  case 'issue':
457  case 'issues':
458  file_put_contents($xmlFile, $this->exportIssues(
459  $args,
460  $journal,
461  null,
462  $opts
463  ));
464  return;
465  }
466  break;
467  }
468  $this->usage($scriptName);
469  }
470 
478  function parseOpts(&$args, $optCodes) {
479  $newArgs = [];
480  $opts = [];
481  $sticky = null;
482  foreach ($args as $arg) {
483  if ($sticky) {
484  $opts[$sticky] = $arg;
485  $sticky = null;
486  continue;
487  }
488  if (!starts_with($arg, '--')) {
489  $newArgs[] = $arg;
490  continue;
491  }
492  $opt = substr($arg, 2);
493  if (in_array($opt, $optCodes)) {
494  $opts[$opt] = true;
495  continue;
496  }
497  if (in_array($opt . ":", $optCodes)) {
498  $sticky = $opt;
499  continue;
500  }
501  }
502  $args = $newArgs;
503  return $opts;
504  }
505 }
506 
507 
TemporaryFileManager
Definition: TemporaryFileManager.inc.php:19
NativeImportExportPlugin\getDescription
getDescription()
Definition: NativeImportExportPlugin.inc.php:51
NativeImportExportPlugin\exportIssues
exportIssues($issueIds, $context, $user, $opts=array())
Definition: NativeImportExportPlugin.inc.php:273
AppLocale\requireComponents
static requireComponents()
Definition: env1/MockAppLocale.inc.php:56
ImportExportPlugin\displayXMLValidationErrors
displayXMLValidationErrors($errors, $xml)
Definition: ImportExportPlugin.inc.php:161
NativeImportExportDeployment
Class configuring the native import/export process to this application's specifics.
Definition: NativeImportExportDeployment.inc.php:19
DAORegistry\getDAO
static & getDAO($name, $dbconn=null)
Definition: DAORegistry.inc.php:57
NativeImportExportPlugin\usage
usage($scriptName)
Definition: NativeImportExportPlugin.inc.php:317
ImportExportPlugin\isRelativePath
isRelativePath($url)
Definition: ImportExportPlugin.inc.php:103
NativeImportExportPlugin
Native XML import/export plugin.
Definition: NativeImportExportPlugin.inc.php:18
NativeImportExportPlugin\display
display($args, $request)
Definition: NativeImportExportPlugin.inc.php:67
NativeImportExportPlugin\importSubmissions
importSubmissions($importXml, $filter, $deployment)
Definition: NativeImportExportPlugin.inc.php:305
ImportExportPlugin
Abstract class for import/export plugins.
Definition: ImportExportPlugin.inc.php:18
ImportExportPlugin\getExportFileName
getExportFileName($basePath, $objectsFileNamePart, $context, $extension='.xml')
Definition: ImportExportPlugin.inc.php:152
JSONMessage
Class to represent a JSON (Javascript Object Notation) message.
Definition: JSONMessage.inc.php:18
ImportExportPlugin\getExportPath
getExportPath()
Definition: ImportExportPlugin.inc.php:140
NativeImportExportPlugin\executeCLI
executeCLI($scriptName, &$args)
Definition: NativeImportExportPlugin.inc.php:327
PKPTemplateManager\getManager
static & getManager($request=null)
Definition: PKPTemplateManager.inc.php:1239
NativeImportExportPlugin\exportSubmissions
exportSubmissions($submissionIds, $context, $user, $opts=array())
Definition: NativeImportExportPlugin.inc.php:233
Plugin\getTemplateResource
getTemplateResource($template=null, $inCore=false)
Definition: Plugin.inc.php:349
Plugin\$request
$request
Definition: Plugin.inc.php:68
NativeImportExportPlugin\parseOpts
parseOpts(&$args, $optCodes)
Definition: NativeImportExportPlugin.inc.php:478
Plugin\addLocaleData
addLocaleData($locale=null)
Definition: Plugin.inc.php:454
FileManager
Class defining basic operations for file management.
Definition: FileManager.inc.php:35
NativeImportExportPlugin\getName
getName()
Definition: NativeImportExportPlugin.inc.php:35
NativeImportExportPlugin\getPluginSettingsPrefix
getPluginSettingsPrefix()
Definition: NativeImportExportPlugin.inc.php:58
NativeImportExportPlugin\getDisplayName
getDisplayName()
Definition: NativeImportExportPlugin.inc.php:43
PKPServices\get
static get($service)
Definition: PKPServices.inc.php:49