I don't have the time right now to go more in depth, but here is all the information I have from a 5-minute scan.
In a custom component with a form field class extending JFormFieldCheckboxes
(a subclass of JFormFieldList
) and overloading the JFormFieldList::getOptions()
method , calling $this->form->renderField('foo')
in the layout is causing the getOptions()
method to be called twice, resulting in duplicate database queries.
The common parts of stack trace from the trace on the database query in the debug output (note that the real component name and view are replaced with "com_component" and "component", the real identifiers are not important to this issue):
14 | Joomla\CMS\Form\FormField->renderField() | JROOT/libraries/src/Form/Form.php:670
13 | Joomla\CMS\Form\Form->renderField() | JROOT/administrator/components/com_component/views/component/tmpl/edit.php:187
12 | include JROOT/administrator/components/com_component/views/component/tmpl/edit.php | JROOT/libraries/src/MVC/View/HtmlView.php:701
11 | Joomla\CMS\MVC\View\HtmlView->loadTemplate() | JROOT/libraries/src/MVC/View/HtmlView.php:230
10 | Joomla\CMS\MVC\View\HtmlView->display() | JROOT/administrator/components/com_component/views/component/view.html.php:73
9 | ComponentViewComponent->display() | JROOT/administrator/components/com_component/controller.php:109
8 | ComponentController->display() | JROOT/libraries/src/MVC/Controller/BaseController.php:710
7 | Joomla\CMS\MVC\Controller\BaseController->execute() | JROOT/administrator/components/com_component/component.php:25
6 | require_once JROOT/administrator/components/com_component/component.php | JROOT/libraries/src/Component/ComponentHelper.php:402
5 | Joomla\CMS\Component\ComponentHelper::executeComponent() | JROOT/libraries/src/Component/ComponentHelper.php:377
4 | Joomla\CMS\Component\ComponentHelper::renderComponent() | JROOT/libraries/src/Application/AdministratorApplication.php:101
3 | Joomla\CMS\Application\AdministratorApplication->dispatch() | JROOT/libraries/src/Application/AdministratorApplication.php:159
2 | Joomla\CMS\Application\AdministratorApplication->doExecute() | JROOT/libraries/src/Application/CMSApplication.php:196
1 | Joomla\CMS\Application\CMSApplication->execute() | JROOT/administrator/index.php:51
Unique portions of each trace are below.
Trace 1, starts at the field's getInput()
method:
19 | JDatabaseDriverMysqli->execute() | JROOT/libraries/joomla/database/driver.php:1701
18 | JDatabaseDriver->loadObjectList() | JROOT/administrator/components/com_component/models/fields/something.php:42
17 | JFormFieldSomething->getOptions() | JROOT/libraries/joomla/form/fields/checkboxes.php:163
16 | JFormFieldCheckboxes->getLayoutData() | JROOT/libraries/joomla/form/fields/checkboxes.php:114
15 | JFormFieldCheckboxes->getInput() | JROOT/libraries/src/Form/FormField.php:975
Trace 2, starts at the field's getLabel()
method:
19 | JDatabaseDriverMysqli->execute() | JROOT/libraries/joomla/database/driver.php:1701
18 | JDatabaseDriver->loadObjectList() | JROOT/administrator/components/com_component/models/fields/something.php:42
17 | JFormFieldSomething->getOptions() | JROOT/libraries/joomla/form/fields/checkboxes.php:163
16 | JFormFieldCheckboxes->getLayoutData() | JROOT/libraries/src/Form/FormField.php:765
15 | Joomla\CMS\Form\FormField->getLabel() | JROOT/libraries/src/Form/FormField.php:976
For completeness, a pseudo-version of the custom form field class which isn't much different than other classes in core:
class JFormFieldSomething extends JFormFieldCheckboxes
{
protected $type = 'something';
protected function getOptions()
{
$db = JFactory::getDbo();
$db->setQuery(
$db->getQuery(true)
->select($db->quoteName(['display_value', 'storage_value'], ['text', 'value']))
->from('#__component')
);
return array_merge(parent::getOptions(), $db->loadObjectList());
}
}
Labels |
Added:
?
|
I honestly have no idea. I tried to avoid the internals of the Form API because it just makes me cringe, so I have no idea what's actually going into the rendering that causes both the input and the label to need the options, and why this results in two separate code paths rendering them in the case of a checkboxes field class. But if rendering through the suggested API can cause multiple repeated calls like this, with uncached results being given for duplicated parameter sets, then to me it's a sign there might be other parts of the Form API that aren't easily profiled because there is no persistent storage of the debug plugin data (so all POST requests are black boxes) that might be doing the same and causing inadvertent performance issues (which, in the case of one of this project's custom list form fields, iterates over a database table with over 500 rows, so these repeated calls can add up).
Has anybody had any success with this?
I have a similar problem when extending JFormFieldList
, and using a subform.repeatable-table
.
the getInput()
or getLayoutData()
calls getOptions()
twice for every single row in the table.
I'm making an API call to populate these fields, in some circumstances, this can result in up to 32 API calls.
There's got to be a way to cache the results of the first response when dealing with repeatable-tables?
No decision has been made on core side. But in your own custom field you can cache data however you want.
Labels |
Added:
No Code Attached Yet
bug
Removed: ? |
Status | New | ⇒ | Closed |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2024-01-25 15:16:04 |
Closed_By | ⇒ | Fedik |
Should this really be handled in base class or should subclasses handle this in their own
getOptions()
method?