Insert in submission_settings table

Hi to all members,

I have a big problem in Ojs 3.2.0.3 version, I can’t insert anything in the submission_setting table.
This is my code:

$submissionDao = DAORegistry::getDAO('SubmissionDAO'); /* @var $submissionDao SubmissionDAO */
    $submission = $submissionDao->getById($articleId);
    $submissionDao->updateObject($submission);

I know that in new version removed many functions like a “getAdditionalFieldNames” in SubmissionDAO but I used it to add some feature to submission_setting table, and I don’t know how can I do it in new version?

Please help me

1 Like

Hi @mbabaei,

I think you’d need to hook in the Schema: HookRegistry::register('Schema::get::submission', array($this, 'addToSchema'));

Implement addToSchema method. Here is an example for the publication_settings:

If you are planning to edit submission, e.g., do something when form is saved with a new value, look at SubmissionService and PKPSubmissionService in your example, e.g., it’s possible to use Submission::edit hook for this. Example for Publication:

1 Like

Hi to @Vitaliy @mbabaei and all further members,

my goal is to add another setting to the publication_settings to store a further property for the submission. I tried it just the way you described it. But the scheme is not extended accordingly. Which step is missing? I am very glad about any help!

Here you can see my code snippets:

HookRegistry::register('Schema::get::publication', array($this, 'addToSchema'));
HookRegistry::register('Publication::edit', array($this, 'editPublication'));

public function addToSchema($hookName, $args) {
	$schema = $args[0];
	$propertyId = '{
		"type": "integer",
		"multilingual": true,
		"apiSummary": true,
		"validation": [
			"nullable"
		]
	}';
	$propertyIdDecoded = json_decode($propertyId);
	$property = '{
		"type": "string",
		"multilingual": true,
		"apiSummary": true,
		"validation": [
			"nullable"
		]
	}';
	$propertyDecoded = json_decode($property);

	$schema->properties->{'anotherTest'} = (object) [
		'type' => 'string',
		'apiSummary' => true,
		'validation' => ['nullable'],
	];

	$schema->properties->{'geoOJS::propertyId'} = $propertyIdDecoded;
	$schema->properties->{'geoOJS::property'} = $propertyDecoded;
}

function editPublication(string $hookname, array $args) {
	$newPublication = $args[0];
	$params = $args[2];

	$localePare = $params['geoOJS::propertyId'];	
}

Hi @tnier01,

At the first glance looks correct. I think this will work:

$newPublication->setData('geoOJS::propertyId', $yourdata, $localeKey);

But let me know if you are looking for something different.

1 Like

Thanks for the quick answer, that was what I was looking for!

Hi @Vitaliy and all further members,

I got a further question regarding this topic. I have successfully saved the schema and stored my data in the database. But after submitting, the data I stored before is no longer available in the database. So not only the setting_value but also setting_name etc. is not available anymore. My schema extension was practically undone.
I would like to access my saved data in the article view similar to here, but unfortunately my saved elements are no longer available. I can already retrieve other initially existing elements. It happens at the moment during the workflow, when I assign the submission to an issue.
How can I make sure that my additional data in the publication_settings is still available after the submission has been published? I am very glad about any help!

Here you can see my code snippets:

HookRegistry::register('Schema::get::publication', array($this, 'addToSchema'));
HookRegistry::register('Publication::edit', array($this, 'editPublication'));

public function addToSchema($hookName, $args)
{
	$schema = $args[0];

	$exampleProperties = '{
		"type": "string",
		"multilingual": true,
		"apiSummary": true,
		"validation": [
			"nullable"
		]
	}';
	$examplePropertiesDecoded = json_decode($exampleProperties);
	$schema->properties->{'examplePlugin::exampleProperties'} = $examplePropertiesDecoded;
}

function editPublication(string $hookname, array $args)
{
	$newPublication = $args[0];
	$params = $args[2];

	$exampleProperties = 'Hey I am here';

	$newPublication->setData('examplePlugin::exampleProperties', $exampleProperties, null);
}

According to the statement the value is multilingual:

"multilingual": true,

But you are passing null for the locale as a parameter:

$newPublication->setData('examplePlugin::exampleProperties', $exampleProperties, null);

I think there should be either a valid locale or $exampleProperties shouldn’t be marked as multilingual. If it’s not the reason, check what data you are passing when saving a form, I mean examplePlugin::exampleProperties property (is it null).

Thanks for your advise @Vitaliy, but I do not think that this was the main problem! But I was able to narrow down the problem a bit.
My goal is to save both a date and a JSON file. This I get via a post request over the template of the javascript. The two variables will be saved in the publication_settings as I want them to be. But the variables are deleted from the database as soon as the issue for publishing the submission is defined.
The problem is that the variables are stored as strings in double quotes and not in single quotes. I have tried it with single quotes for a test, then the data is not deleted. However, I have not found a way to save the data with single quotes only or to get them from javascript via the template in single quotes.
Does anyone else have an idea?
Which alternative possibilities are there to extend the schema concerning the type? What other data types are there besides string, integer? Is there a index where all possibilities are listed?
I am very glad about any help!

Take a look at PKPSchemaService class, I see several methods there that deal with those types, e.g.: https://github.com/pkp/pkp-lib/blob/222a310adcad88e335ec2d6990d9ff2623d3a992/classes/services/PKPSchemaService.inc.php#L237

I wasn’t able to reproduce it with a simple string. If you want to save the object, I see from the code that it’s also supported (there is type object in schema).
Also, can you check that you are trying to save in setting_value less than 64kb?

Hi @Vitaliy and all further members,

I tried to save my json object as type “object”, but only the following sequence was saved: a:0:{}. Here you can see my decoded json object:

And here my json object as string:

I am relatively sure that it is not because the variable I want to store is too large.
My repository is online on github if this helps with a possible repoduction. With the link I have marked the place where I load the string in PHP from the .tpl file using Post request. It will be saved in the database, but will be deleted as soon as you change any settings like the issue or the meta data before “Schedule For Publication”.
But in the meantime I am no longer convinced that it is because of the quotes, although the behavior described in my last post seems strange to me. Because even if I want to save a single number from my json object as number it will be deleted again.

However, I noticed one more thing! I noticed that you also use this file, I assume that it is for the last editing before “Schedule for Publication”. Unfortunately I don’t quite see through the file yet. What is happening here? Is it possible that not doing this in my repository is the reason that my saved data is deleted or is there something else that’s missing ?

It’s for adding additional radio input field into the publication form. It’s practically a new tab: https://github.com/Vitaliy-1/JATSParserPlugin/blob/21425c486f0f157cd8dc6b829322cd32159dd408/templates/workflowJatsFulltext.tpl with a form attached as can be seen from the screenshot. The front-end part is rendered by a ui-library based on Vue.js.
Data to the form is assigned here.

$newPublication->setData('geoOJS::timestamp', $datetimes, null);
$newPublication->setData('geoOJS::spatialProperties', $spatialProperties, null);

According to the setData method, if 3rd parameter is null there are 2 possibilities, add to all locales or, if value is null, to unset the data.
So, if $_POST['datetimes'] and $_POST['spatialProperties'] are null during editPublication execution, the data are going to be deleted according to your code. I suspect you found that the hook is being executed during Schedule For Publication.

Maybe check if keys exist in the post array or use other conditions that will prevent unwanted behavior.

1 Like

Hi @Vitaliy, thanks for your advice. I was not aware that the hook 'Publication::edit' is also executed during Schedule For Publication. Thanks for the hint, so my error is clear and I was able to fix the problem!
Another question has now come to my mind in this context. Which hook do I have to use to change the template during Schedule For Publication? So to edit the template of this screenshot?
Bildschirmfoto 2020-08-17 um 11.08.55

Are there other places apart from these two where the metadata can be edited or additional ones added?
Is there a general index of hooks, I only found this one so far?

You can debug all hooks that are called during request in HookRegistry::call, $hookName variable contains names.

The template that is general for publication is workflow.tpl. You can find there lines:

{if $metadataEnabled}
	<tab id="metadata" label="{translate key="submission.informationCenter.metadata"}">
		<pkp-form v-bind="components.{$smarty.const.FORM_METADATA}" @set="set" />
	</tab>
{/if}

Here Vue.js is mounted to display the form. It’s a change from OJS 3.1 where all form data was displayed with Smarty.

You can use the hook Form::config::before to access such new forms. In your case, it will be something like:

public function addMetadataFormFields(string $hookName, FormComponent $form): void {
		if ($form->id === 'metadata') do something.
...

JATS Parser Plugin should contain an example, it does the same for the citations form, here: https://github.com/Vitaliy-1/JATSParserPlugin/blob/6ae1f9cd1ad671c7acc257f337e2530eda93bf96/JatsParserPlugin.inc.php#L979

Publication metadata? Hmm, looking at the PKPPublicationService, when a publication is unpublished, it’s cloned, this cloned version is saved with a new status: https://github.com/pkp/pkp-lib/blob/5c45b47cd19d18e4199b94a789e0e10d0a1359e4/classes/services/PKPPublicationService.inc.php#L550. Also there is PKPPublicationService::add when a new publication is added and PKPPublicationService::version, when a new version is created. They all have hooks.

The strange part is that it was just a guess and now, when I debug this, it looks like this hook is executed only once, when editing the form. So, I’m completely confused.

Hi @Vitaliy thanks for your detailed answer.

The hint was helpful for me, I know now how I can integrate further forms directly. Is it possible to include further elements that can use Javascript code, similar to the way submissionMetadataFormFields.tpl can be extended? I would like to enable a map input similar to what I implemented in Submission Step 3 - Enter Metadata?
To sum it up, I would prefer it if there is a way to simply extend the metadata template at this step with another .tpl file using Smarty! Is there such a possibility and if so how? And if not, is there an alternative that would make this idea work?

In my case, I am now relatively certain that the hook Publication::edit was executed in both cases because the data in the database was changed both during Submission Step 3 - Enter Metadata and before Schedule For Publication and I can influence the data which is stored by a function which uses this hook.

Unfortunately, this form (step 3 submission metadata) hasn’t been refactored to work this way yet as metadata form which I described before. The former is used for a submission process and the latter to edit metadata during general workflow. The new form’s architecture is OJS 3.2 feature but still, there are forms that use older code.

In general, some Smarty templates contain hooks where additional data can be inserted. In you case it’s Templates::Submission::SubmissionMetadataForm::AdditionalMetadata: https://github.com/pkp/pkp-lib/blob/e106fc3b246069f06b256801c024d6832d2d7883/templates/submission/submissionMetadataFormFields.tpl#L79 (submissionMetadataFormFields.tpl is included in lib/pkp/templates/submission/form/step3.tpl).
Something like:

HookRegistry::register('Templates::Submission::SubmissionMetadataForm::AdditionalMetadata', array($this, 'displayData'));
...
function displayData(string $hookname, array $args) {
		$templateMgr =& $args[1];
		$output =& $args[2];
        $templateMgr->assign('mydata', $mydata);
		$output .= $templateMgr->fetch($this->getTemplateResource('newTemplatePathStartingFromTemplatesDirectory.tpl'));
}

Example: https://github.com/Vitaliy-1/JATSParserPlugin/blob/6ae1f9cd1ad671c7acc257f337e2530eda93bf96/JatsParserPlugin.inc.php#L713

If hook isn’t added, a template can be overridden from a theme plugin:https://docs.pkp.sfu.ca/pkp-theming-guide/en/child-themes#overriding-templates.

Each Form according to the old architecture extends Form class and it’s possible to interact with it (pass new form data) from a plugin using hooks in the readUserVars, initData and execute methods: https://github.com/pkp/pkp-lib/blob/e106fc3b246069f06b256801c024d6832d2d7883/classes/form/Form.inc.php#L314. E.g., take a look at the Immersion theme using those: https://github.com/pkp/immersion/blob/596488180808b434543f29116bf8efd5a033a213/ImmersionThemePlugin.inc.php#L96-L98

Hi @Vitaliy thanks for your detailed help.
I already was able to add additional data by a smarty template during step 3 submission metadata using the hook Templates::Submission::SubmissionMetadataForm::AdditionalMetadata.
It works fine.

But my issue right now is how to insert something into the metadata area right before Schedule for Publication.
I would like to add a map based on Javscript code at this point.
Bildschirmfoto 2020-08-29 um 12.19.11

In case of the step 3 submission metadata it worked fine with the hook Templates::Submission::SubmissionMetadataForm::AdditionalMetadata::AdditionalMetadata and I was able to extend the original template with a smarty template (geoOJS/geoOJSPlugin.inc.php at master · tnier01/geoOJS · GitHub), but how can I do it here?

I already know how I can insert in general something into this template by the hook Template::Workflow::Publication (lower left corner) but I want to insert something in the Metdata area. It is not a further form I want add, which is possible by the Hook Form::config::before of course. But I want to add a map based on Javscript Code. Is there a way how I can insert something at this point, a map or generally a html element?

Hi @tnier01,

It’s possible through the hook to insert predefined input fields that are supported by the ui-library, like radio input or text area; maps are not supported.

You can try to load external Javascript as described in the plugin guide or through the hook where TemplateManager object is present and limit it to the workflow page. If insert an element in the place you show, this script should run after Vue is mounted. I haven’t experemented with it with the new library. Maybe @NateWr can help you more.

Hi @tnier01,

The forms are fairly constrained in order to ensure that they follow accessibility requirements. You can, however, add a plain HTML field with whatever HTML code that you want to any form. Use the following hook in your plugin to add a plain HTML field to this form:

HookRegistry::register('Form::config::before', function($hookName, $form) {

	// Import the FORM_METADATA constant
	import('lib.pkp.classes.components.forms.publication.PKPMetadataForm');

	// Don't modify any other forms
	if ($form->id !== FORM_METADATA) {
		return;
	}

	// Add a plain HTML field to the form
	$form->addField(new FieldHTML('myFieldName', [
		'label' => 'My Field Name',
		'description' => '<p>Add any HTML code that you want.</p>',
	]));
});

Beware that the Vue.js framework will handle adding and removing this element from the DOM. That means it won’t always be available and this could impact how your map is initialized. You will need to make sure that the map is initialized whenever the field is added to the DOM.

Usually you can do that by simply adding a <script> tag with your JavaScript directly into the HTML that’s being added.

1 Like