No Code Attached Yet bug
avatar mbabker
mbabker
24 Apr 2020

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());
	}
}
avatar mbabker mbabker - open - 24 Apr 2020
avatar joomla-cms-bot joomla-cms-bot - change - 24 Apr 2020
Labels Added: ?
avatar joomla-cms-bot joomla-cms-bot - labeled - 24 Apr 2020
avatar SharkyKZ
SharkyKZ - comment - 27 Apr 2020

Should this really be handled in base class or should subclasses handle this in their own getOptions() method?

avatar mbabker
mbabker - comment - 27 Apr 2020

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).

avatar Fedik
Fedik - comment - 28 Apr 2020

yeah, that an old issue,
the getLayoutData() called for label and for input rendering,
this is true for all fields

I think the $data should be cached somehow

previous issue #13483, that is closed successfully ?

avatar Sma5hley
Sma5hley - comment - 13 Dec 2022

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?

avatar SharkyKZ
SharkyKZ - comment - 13 Dec 2022

No decision has been made on core side. But in your own custom field you can cache data however you want.

avatar Hackwar Hackwar - change - 21 Feb 2023
Labels Added: No Code Attached Yet bug
Removed: ?
avatar Hackwar Hackwar - labeled - 21 Feb 2023
avatar Fedik Fedik - close - 25 Jan 2024
avatar Fedik
Fedik - comment - 25 Jan 2024

Please test #42709

avatar Fedik Fedik - change - 25 Jan 2024
Status New Closed
Closed_Date 0000-00-00 00:00:00 2024-01-25 15:16:04
Closed_By Fedik

Add a Comment

Login with GitHub to post a comment