You're actually doing it as intended within Joomla. Here's a bit of background to explain why you're right, and for the sake of others who may be interested.
Overall the Joomla Form Basic API guide tries to explain how Joomla forms work. The first part of that page treats the subject at a fairly low level, and the second part considers how forms are handled within the Joomla MVC paradigm, which is what we have to deal with in practice.
Forms are loaded in the Model class of the component by calling a library function loadForm()
and passing the filename of the XML file which contains the form.
So when you're setting plugin parameters within Joomla administrator you're in the com_plugins
component, and its Model in administrator/components/com_plugins/src/Model/PluginModel.php will call loadForm()
and pass the filename of the XML file in administrator/components/com_plugins/forms/plugin.xml. If you have a look at that file you'll see the similarity with the standard plugin options shown on the right hand side of the plugin form.
When you display a form on a web page sometimes you want to populate the form fields with data:
if you are editing a database record, then you want to prefill the
fields with their current value in the database
if the user has entered some data into the form and then submitted the
form, but the Joomla server code has found errors in the data, then
when you re-present the form you want to prefill the fields with what he/she previously entered, so that it can be more easily corrected.
Hence the loadForm
function has a parameter which specifies if prefill data should be loaded. If this is set to true then loadForm
will call a callback function loadFormData
which it will expect the component Model to provide. The com_plugins
provides this function: it checks if there's previously entered data on the form, and if not it loads the existing plugin fields from the database record. It doesn't matter that there are more fields in this data object which is built from the database than there are fields in the form XML – Joomla will just take the data items it needs. But notice that to do this seamlessly the name
of each field in the XML file matches the name of the equivalent database column.
Once it has built the data object the com_plugins
function loadFormData
calls a library function preprocessData
, and it's this library function which triggers the 'onContentPrepareData' event whose purpose is to allow plugins to make any desired modification to this data.
The library loadForm
function then calls the component model's preprocessForm
function, and within PluginModel it gets your plugin's manifest XML file and injects the section of this file which is within the <config>
tags into the Form object (which was built from administrator/components/com_plugins/forms/plugin.xml). The fields within the <config>
tags provide the options which are specific to that individual plugin, and these are stored as name-value pairs in a JSON string in the params
field of the database record. That's why you're right to have
<config>
<fields name="params">
...
<field name="provider" label="Provider" type="text" />
as the data will get stored in the params
field as a string {"provider": "xxx"}
.
The library loadForm
function then triggers the event 'onContentPrepareForm', passing the Form instance and the data object, to allow plugins once again to modify data values (or the Form itself).
It doesn't matter whether to choose to modify your data in 'onContentPrepareForm' or in 'onContentPrepareData'. Either way, you can set the data as you're doing:
$data->params['provider'] = 'xxxxxxxxxx';
Next the data object is bound to the Form instance via a bind()
call. You can still modify data values after that, but it's a bit trickier, and you have to use the API methods described in the Form Advanced API guide.
Finally, just a couple things to be aware of.
If you're defining a plugin like this then the onContentPrepareForm and onContentPrepareData functions are going to get called whenever any form is displayed by Joomla, back-end or front-end. So you should always check that it's the form you're interested in by doing
if ($form->getName() === 'com_plugins.plugin') {…}
and also that it's just your own plugin that you're affecting:
if ($data->name === '<your plugin name>') {…}
Also the $data
is held as a Joomla\CMS\Object\CMSObject
instance, and you should really check that it is indeed that type of object before you go accessing the properties. I guess there is the chance that com_plugins could change this in the future to be a Joomla\Registry\Registry
object, and then you'd need to change the getter and setter you use.