Bad performance by recursivly invoking hook_civicrm_config (by civix generated code)
The problem in short
hook_civicrm_config
is called recursively causing CiviCRM to perform bad. Fixing this improves the CiviCRM performance by more than 50%!
This caused by civix generated code in extensions.
The problem long
When Civix generates the skeleton for an extension it adds the following code
/**
* (Delegated) Implements hook_civicrm_config().
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_config
*/
function _shoreditch_civix_civicrm_config(&$config = NULL) {
static $configured = FALSE;
if ($configured) {
return;
}
$configured = TRUE;
$template =& CRM_Core_Smarty::singleton();
$extRoot = dirname(__FILE__) . DIRECTORY_SEPARATOR;
$extDir = $extRoot . 'templates';
if (is_array($template->template_dir)) {
array_unshift($template->template_dir, $extDir);
}
else {
$template->template_dir = array($extDir, $template->template_dir);
}
$include_path = $extRoot . PATH_SEPARATOR . get_include_path();
set_include_path($include_path);
}
The line $template =& CRM_Core_Smarty::singleton();
is causing the trouble because of the following in CRM_Core_Smarty
/**
* Class constructor.
*
* @return CRM_Core_Smarty
*/
public function __construct() {
parent::__construct();
}
private function initialize() {
$config = CRM_Core_Config::singleton();
...
Above code is calling the CRM_Core_Config::singleton()
which in turns invokes the hook_civicrm_config again...
Performance Measurements
In my local environment a page load takes 1.6 seconds. With a quick and dirty fix in my local environment it brings te page load down to 0.6 seconds.
My local environment has around 25 extensions installed.
Solution
The ideal solution would be to add the extensions path to the Civi Container so that it resides in code in templates_c/CachedContainer.nnn.php I do think this is the best performing option.
Ideally we want to fix the hook_civicrm_config in every extension but we don't want them to break backwards compatibility.
So my way to create an ideal solution is the following:
- Add the extensions template directory to the CiviCRM Container (and keeping in mind that extension developers might want to add their own custom template directory)
- Fix the skeleton generated by Civix
- Come up with a nasty hack so that extensions still work but performance is improved
- Tell extension developers about this by a blog post/mailing and by adding a status message when the old civix code is still in use