OJS 3.3 registering additional filters for XML Export

Hello,
as discussed over on github: Extend native import/export plugin to include additional entities · Issue #3261 · pkp/pkp-lib · GitHub
I am currently looking for a way to export single articles from OJS, including all their metadata, files, discussions, reviews etc.

A few details on the project:
We’re trying to establish some kind of long term storage for OJS articles. Since the requirements of the project are out of my hand, this means storage as XML, either with base64 encoded files, or files extra, all other metadata in the XML. Storage will be triggered once on a per-article basis, probably using DOI.
Storage may not include any additional personal data (email adresses, IPs, passwords, etc.) of persons not connected with the article, so a full dump is not feasible.

As of now I have two different approaches:

  • Try to “hack” the system from the outside, using shellscript or php, reading out the config.php and basically writing my own SQL to XML script. This has the benefit of being robust against changes in the OJS software. But not against changes in the OJS DB-Structure. I have started to analyze the DB-Structure and I think this option is not really feasible
  • Try to extend the XML-Export functionality. I have cloned the native XML-Import-Export plugin, stripped away features I don’t need and tried to change the filters, to export the data I need. This seems more feasible, but I have encountered some problems.

Problems with the XML-Export:

  • I lack a clear documentation of how to extract certain data from the DB. I think this is done in the filters section i.e. ArticleNativeXmlFilter.inc.php but I struggle to find it
  • I don’t know where and when new filters are registered. I understand that they have to be passed to the DB at some point, since there is a filters table, but I can’t find that point in the code. Is this done in installation? Can I trigger some kind of installation event for my plugin?

I understand this is a quite complicated topic and would deeply appreciate any help on the subject.

Best Regards,
Karl.

1 Like

Hi Karl,

If you’d like to create your own filters or extend the Native XML import/export plugin, there is a filterConfig.xml file present in the plugin’s filters directory. This XML file defines the filter classes available to the plugin, and in what context they are used. There are elements in there as well as a symbolic attribute that tells the code which filter to use for which conversion (for example, native-xml=>article meaning importing XML to create an Article class, or publication=>native-xml which would be the filter that takes a Publication class and creates the XML stub for it).

This filterConfig.xml file is read when the plugin is installed or upgraded since that is when the filters table is updated. You could also manually create the entries in the filters table in the database.

Best
Jason

Hello Jason,
thanks, that’s very helpful.
Since I practically copied the Code from the native XML plugin, it comes auto-installed. I guess I should change that.

Cheers, Karl.

Hello Jason,
unfortunately I wasn’t able to find the installation of the plugin in the code.
Since the original plugin comes pre-installed and without a settings.xml (as opposed to other Plugins, like blocks for example) I don’t know where to add a possibility to install/uninstall the plugin.
Is there any documentation on this?

Thanks!
Best Regards,
Karl.

Hi Karl,

I’m not sure what you mean by the “installation” of the plugin. Typically plugins are either pre-installed, or they are installed by uploading a tar.gz file via the Plugins tab, or by untarring a tar.gz file in the plugins/ directory and then running:

php lib/pkp/tools/installPluginVersion.php plugins/whatever/yourPlugin/version.xml

It’s the “version.xml” file that must be in every plugin directory, including preinstalled ones, that is used by OJS to create the entries in the plugin_settings and versions database tables.

At present there is no easy way to uninstall a plugin completely. You can disable them in the plugins grid, but if you want to truly remove one you need to also delete the entries in those two database tables as well.

There is documentation on our Dochub about plugin development: Plugin Guide for OJS and OMP

Best
Jason

Hello Jason,
thanks again for your help, this has been very helpful. With the documentation provided, I was able to install the plugin.

However, it seems the filter I added for this plugin, was not installed, as I can’t find it in the filters table in the DB. When I try to export something I get the following error message:

[php7:error] [pid 4127] [client ---] PHP Fatal error:  Uncaught Error: Call to a member function setDeployment() on null in /var/www/ojs_test/plugins/importexport/LZA-export/LZAExportPlugin.inc.php:240
Stack trace:
#0 /var/www/ojs_test/plugins/importexport/LZA-export/LZAExportPlugin.inc.php(198): LZAExportPlugin->exportSubmissions(Array, Object(Journal), Object(User))
#1 /var/www/ojs_test/lib/pkp/pages/management/PKPToolsHandler.inc.php(94): LZAExportPlugin->display(Array, Object(Request))
#2 /var/www/ojs_test/lib/pkp/classes/core/PKPRouter.inc.php(395): PKPToolsHandler->importexport(Array, Object(Request))
#3 /var/www/ojs_test/lib/pkp/classes/core/PKPPageRouter.inc.php(246): PKPRouter->_authorizeInitializeAndCallRequest(Array, Object(Request), Array, false)
#4 /var/www/ojs_test/lib/pkp/classes/core/Dispatcher.inc.php(144): PKPPageRouter->route(Object(Request))
#5 /var/www/ojs_test/lib/pkp/classes/core/PKPApplication.inc.php(362): Dispatcher->dispatch(Object(Request))
#6 /var/www/ojs_test/index.php(68): PKPApplication->execute()
#7 {main}
  thrown in /var/www/ojs_test/plugins/importexport/LZA-export/LZAExportPlugin.inc.php on line 240, referer: ...

Through some previous error hunting I have concluded that this error is thrown, when the search for the filters used by the export in the database returns null.

Is there any way to install the filters manually? Or am I missing something in the installation?

Thanks!
Best Regards,
Karl.

Hi Karl,

Did you add your new filter to the filterConfig.xml file before you installed the plugin? You could also try manually creating the record in the filters table in the database, if it is not present.

Best
Jason

Hey Jason,
thanks for the answer.

filterConfig looks like this:

<filterConfig>
	<filterGroups>
		<!-- Native XML article output -->
		<filterGroup
			symbolic="article=>LZA-export-xml"
			displayName="plugins.importexport.LZA-export.displayName"
			description="plugins.importexport.LZA-export.description"
			inputType="class::classes.submission.Submission[]"
			outputType="xml::schema(plugins/importexport/LZA-export/LZA-export.xsd)" />

		<!-- Native XML issue output -->
		<filterGroup
			symbolic="issue=>LZA-export-xml"
			displayName="plugins.importexport.LZA-export.displayName"
			description="plugins.importexport.LZA-export.description"
			inputType="class::classes.issue.Issue[]"
			outputType="xml::schema(plugins/importexport/LZA-export/LZA-export.xsd)" />
	</filterGroups>
	<filters>
		<!-- Native XML article output -->
		<filter
			inGroup="article=>LZA-export-xml"
			class="plugins.importexport.LZA-export.filter.ArticleLZAXmlFilter"
			isTemplate="0" />
		<filter
			inGroup="issue=>LZA-export-xml"
			class="plugins.importexport.LZA-export.filter.IssueLZAXmlFilter"
			isTemplate="0" />
		<!-- Native XML issue input -->
	</filters>
</filterConfig>

I have tried adding the entries manually to the filters table, but I still got the same error. I speculated that the “filter group” has to be defined somehow and that would be missing when adding the filters manually.

Hey @KBodarwe

There is also a filter_groups table that may need some attention too. You may also want to try turning the debug option in your config file to On, and get the very verbose query output and see what it’s trying to do right before it fails.

Cheers,
Jason

Thanks @jnugent

I have added the entries into filters and filter_groups manually. Also turned debug on, that’s very helpful.
Now I get a new error, when trying to Export. I think I’m getting closer to the issue.
There seems to be an error while instantiating the Class:

[Wed Oct 20 09:48:30.633845 2021] [php7:error] [pid 15179] [client ...] PHP Fatal error:  Uncaught Exception: Error while instantiating class "plugins.importexport.LZA-export.filter.ArticleLZAXmlFilter" as filter! in /var/www/ojs_test/lib/pkp/classes/filter/FilterDAO.inc.php:455
Stack trace:
#0 /var/www/ojs_test/lib/pkp/classes/filter/FilterDAO.inc.php(481): FilterDAO->_newDataObject('plugins.importe...', 28)
#1 /var/www/ojs_test/lib/pkp/classes/filter/FilterDAO.inc.php(308): FilterDAO->_fromRow(Array)
#2 /var/www/ojs_test/plugins/importexport/LZA-export/LZAExportPlugin.inc.php(237): FilterDAO->getObjectsByGroup('article=>LZA-ex...')
#3 /var/www/ojs_test/plugins/importexport/LZA-export/LZAExportPlugin.inc.php(198): LZAExportPlugin->exportSubmissions(Array, Object(Journal), Object(User))
#4 /var/www/ojs_test/lib/pkp/pages/management/PKPToolsHandler.inc.php(94): LZAExportPlugin->display(Array, Object(Request))
#5 /var/www/ojs_test/lib/pkp/classes/core/PKPRouter.inc.php(395): PKPToolsHandler->importexport(Array, Object(Request))
#6 /var/www/ojs_test/lib/pkp/classes/core/PKPPageRouter.inc.php(246): PK in /var/www/ojs_test/lib/pkp/classes/filter/FilterDAO.inc.php on line 455, referer: ...

the relevant lines seem to be:

$filter = instantiate($filterClassName, 'PersistableFilter', null, 'execute', $filterGroup); /* @var $filter PersistableFilter */
if (!is_object($filter)) throw new Exception('Error while instantiating class "'.$filterClassName.'" as filter!');

I’m going to doublecheck my Filter Names etc.

Cheers,
Karl.

I’ve double checked all my classes and files, and there’s no typos to be found. I’m a little lost as to what is causing the error above.

Any more insight on what could cause this?

Thanks,
Karl.