From 2f255668615b24d332028ebd508b461611ecc605 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Sun, 29 Aug 2021 20:25:39 -0400 Subject: [PATCH] APIv4 - Add caching in Entity.get to avoid repeated file scanning --- CRM/Core/BAO/ConfigSetting.php | 5 +- CRM/Core/Component.php | 5 +- Civi/Api4/Action/Entity/Get.php | 94 ++++++++++++++++++--------------- 3 files changed, 57 insertions(+), 47 deletions(-) diff --git a/CRM/Core/BAO/ConfigSetting.php b/CRM/Core/BAO/ConfigSetting.php index 7fd74c1aeb..972ad1260d 100644 --- a/CRM/Core/BAO/ConfigSetting.php +++ b/CRM/Core/BAO/ConfigSetting.php @@ -360,11 +360,8 @@ class CRM_Core_BAO_ConfigSetting { * @param array $enabledComponents */ public static function setEnabledComponents($enabledComponents) { - // fix the config object. update db. + // The on_change trigger on this setting will trigger a cache flush Civi::settings()->set('enable_components', $enabledComponents); - - // also force reset of component array - CRM_Core_Component::getEnabledComponents(TRUE); } /** diff --git a/CRM/Core/Component.php b/CRM/Core/Component.php index 6a3123bd90..7661eb3e04 100644 --- a/CRM/Core/Component.php +++ b/CRM/Core/Component.php @@ -37,7 +37,6 @@ class CRM_Core_Component { private static function &_info($force = FALSE) { if (!isset(Civi::$statics[__CLASS__]['info'])|| $force) { Civi::$statics[__CLASS__]['info'] = []; - $c = []; $config = CRM_Core_Config::singleton(); $c = self::getComponents(); @@ -122,9 +121,13 @@ class CRM_Core_Component { return self::_info($force); } + /** + * Triggered by on_change callback of the 'enable_components' setting. + */ public static function flushEnabledComponents() { unset(Civi::$statics[__CLASS__]); CRM_Core_BAO_Navigation::resetNavigation(); + Civi::cache('metadata')->clear(); } /** diff --git a/Civi/Api4/Action/Entity/Get.php b/Civi/Api4/Action/Entity/Get.php index 06e262c34b..024ffadba2 100644 --- a/Civi/Api4/Action/Entity/Get.php +++ b/Civi/Api4/Action/Entity/Get.php @@ -57,7 +57,7 @@ class Get extends \Civi\Api4\Generic\BasicGetAction { // Fetch custom entities unless we've already fetched everything requested if (!$namesRequested || array_diff($namesRequested, array_keys($entities))) { - $this->addCustomEntities($entities); + $entities = array_merge($entities, $this->getCustomEntities()); } ksort($entities); @@ -81,59 +81,69 @@ class Get extends \Civi\Api4\Generic\BasicGetAction { * @return \Civi\Api4\Generic\AbstractEntity[] */ private function getAllApiClasses() { - $classNames = []; - $locations = array_merge([\Civi::paths()->getPath('[civicrm.root]/Civi.php')], - array_column(\CRM_Extension_System::singleton()->getMapper()->getActiveModuleFiles(), 'filePath') - ); - foreach ($locations as $location) { - $dir = \CRM_Utils_File::addTrailingSlash(dirname($location)) . 'Civi/Api4'; - if (is_dir($dir)) { - foreach (glob("$dir/*.php") as $file) { - $className = 'Civi\Api4\\' . basename($file, '.php'); - if (is_a($className, 'Civi\Api4\Generic\AbstractEntity', TRUE)) { - $classNames[] = $className; + $cache = \Civi::cache('metadata'); + $classNames = $cache->get('api4.entities.classNames', []); + if (!$classNames) { + $locations = array_merge([\Civi::paths()->getPath('[civicrm.root]/Civi.php')], + array_column(\CRM_Extension_System::singleton()->getMapper()->getActiveModuleFiles(), 'filePath') + ); + foreach ($locations as $location) { + $dir = \CRM_Utils_File::addTrailingSlash(dirname($location)) . 'Civi/Api4'; + if (is_dir($dir)) { + foreach (glob("$dir/*.php") as $file) { + $className = 'Civi\Api4\\' . basename($file, '.php'); + if (is_a($className, 'Civi\Api4\Generic\AbstractEntity', TRUE)) { + $classNames[] = $className; + } } } } + $cache->set('api4.entities.classNames', $classNames); } return $classNames; } /** - * Add custom-field pseudo-entities + * Get custom-field pseudo-entities * - * @param $entities - * @throws \API_Exception + * @return array[] */ - private function addCustomEntities(&$entities) { - $customEntities = CustomGroup::get() - ->addWhere('is_multiple', '=', 1) - ->addWhere('is_active', '=', 1) - ->setSelect(['name', 'title', 'help_pre', 'help_post', 'extends', 'icon']) - ->setCheckPermissions(FALSE) - ->execute(); - $baseInfo = CustomValue::getInfo(); - foreach ($customEntities as $customEntity) { - $fieldName = 'Custom_' . $customEntity['name']; - $baseEntity = CoreUtil::getApiClass(CustomGroupJoinable::getEntityFromExtends($customEntity['extends'])); - $entities[$fieldName] = [ - 'name' => $fieldName, - 'title' => $customEntity['title'], - 'title_plural' => $customEntity['title'], - 'description' => ts('Custom group for %1', [1 => $baseEntity::getInfo()['title_plural']]), - 'paths' => [ - 'view' => "civicrm/contact/view/cd?reset=1&gid={$customEntity['id']}&recId=[id]&multiRecordDisplay=single", - ], - 'icon' => $customEntity['icon'] ?: NULL, - ] + $baseInfo; - if (!empty($customEntity['help_pre'])) { - $entities[$fieldName]['comment'] = $this->plainTextify($customEntity['help_pre']); - } - if (!empty($customEntity['help_post'])) { - $pre = empty($entities[$fieldName]['comment']) ? '' : $entities[$fieldName]['comment'] . "\n\n"; - $entities[$fieldName]['comment'] = $pre . $this->plainTextify($customEntity['help_post']); + private function getCustomEntities() { + $cache = \Civi::cache('metadata'); + $entities = $cache->get('api4.entities.custom'); + if (!isset($entities)) { + $entities = []; + $customEntities = CustomGroup::get() + ->addWhere('is_multiple', '=', 1) + ->addWhere('is_active', '=', 1) + ->setSelect(['name', 'title', 'help_pre', 'help_post', 'extends', 'icon']) + ->setCheckPermissions(FALSE) + ->execute(); + $baseInfo = CustomValue::getInfo(); + foreach ($customEntities as $customEntity) { + $fieldName = 'Custom_' . $customEntity['name']; + $baseEntity = CoreUtil::getApiClass(CustomGroupJoinable::getEntityFromExtends($customEntity['extends'])); + $entities[$fieldName] = [ + 'name' => $fieldName, + 'title' => $customEntity['title'], + 'title_plural' => $customEntity['title'], + 'description' => ts('Custom group for %1', [1 => $baseEntity::getInfo()['title_plural']]), + 'paths' => [ + 'view' => "civicrm/contact/view/cd?reset=1&gid={$customEntity['id']}&recId=[id]&multiRecordDisplay=single", + ], + 'icon' => $customEntity['icon'] ?: NULL, + ] + $baseInfo; + if (!empty($customEntity['help_pre'])) { + $entities[$fieldName]['comment'] = $this->plainTextify($customEntity['help_pre']); + } + if (!empty($customEntity['help_post'])) { + $pre = empty($entities[$fieldName]['comment']) ? '' : $entities[$fieldName]['comment'] . "\n\n"; + $entities[$fieldName]['comment'] = $pre . $this->plainTextify($customEntity['help_post']); + } } + $cache->set('api4.entities.custom', $entities); } + return $entities; } /** -- 2.25.1