From c0c5346b2a14c696798083d83a2bddad1715d372 Mon Sep 17 00:00:00 2001 From: benjamin Date: Mon, 25 Nov 2024 17:16:53 +0000 Subject: [PATCH] CachedDAOGetAction - generalise CustomGroup.get caching --- Civi/Api4/CustomGroup.php | 9 ++- .../CachedDAOGetAction.php} | 66 +++++++++++++++---- 2 files changed, 58 insertions(+), 17 deletions(-) rename Civi/Api4/{Action/CustomGroup/Get.php => Generic/CachedDAOGetAction.php} (55%) diff --git a/Civi/Api4/CustomGroup.php b/Civi/Api4/CustomGroup.php index 4b13fda73893..2c2d14438013 100644 --- a/Civi/Api4/CustomGroup.php +++ b/Civi/Api4/CustomGroup.php @@ -10,6 +10,8 @@ */ namespace Civi\Api4; +use Civi\Api4\Generic\CachedDAOGetAction; + /** * CustomGroup entity. * @@ -25,11 +27,12 @@ class CustomGroup extends Generic\DAOEntity { /** * @param bool $checkPermissions - * @return Action\CustomGroup\Get + * @return Generic\CachedDAOGetAction */ public static function get($checkPermissions = TRUE) { - return (new Action\CustomGroup\Get(__CLASS__, __FUNCTION__)) - ->setCheckPermissions($checkPermissions); + return (new CachedDAOGetAction(__CLASS__, __FUNCTION__, function (CachedDAOGetAction $action) { + return \CRM_Core_BAO_CustomGroup::getAll(); + }))->setCheckPermissions($checkPermissions); } } diff --git a/Civi/Api4/Action/CustomGroup/Get.php b/Civi/Api4/Generic/CachedDAOGetAction.php similarity index 55% rename from Civi/Api4/Action/CustomGroup/Get.php rename to Civi/Api4/Generic/CachedDAOGetAction.php index 5ad9da1f1193..4350993d959c 100644 --- a/Civi/Api4/Action/CustomGroup/Get.php +++ b/Civi/Api4/Generic/CachedDAOGetAction.php @@ -10,19 +10,17 @@ +--------------------------------------------------------------------+ */ -namespace Civi\Api4\Action\CustomGroup; +namespace Civi\Api4\Generic; -use Civi\Api4\Generic\Result; -use Civi\Api4\Generic\Traits\ArrayQueryActionTrait; -use Civi\Api4\Generic\Traits\PseudoconstantOutputTrait; +use Civi\API\Exception\NotImplementedException; /** * @inheritDoc * */ -class Get extends \Civi\Api4\Generic\DAOGetAction { - use ArrayQueryActionTrait; - use PseudoconstantOutputTrait; +class CachedDAOGetAction extends \Civi\Api4\Generic\DAOGetAction { + use Traits\ArrayQueryActionTrait; + use Traits\PseudoconstantOutputTrait; /** * @var bool @@ -35,10 +33,33 @@ class Get extends \Civi\Api4\Generic\DAOGetAction { */ protected ?bool $useCache = NULL; + /** + * @var callable + * Function(BasicGetAction $thisAction): array[] + */ + private $cacheGetter; + + /** + * Cached DAO Get constructor. + * + * Pass a function that returns the cached records + * The cache should contain all the fields in the + * EntityRepository schema for this entity. If not override + * this class and override getCachedFields as well + * + * @param string $entityName + * @param string $actionName + * @param callable $getter + */ + public function __construct($entityName, $actionName, $cacheGetter = NULL) { + parent::__construct($entityName, $actionName); + $this->cacheGetter = $cacheGetter; + } + /** * @param \Civi\Api4\Generic\Result $result * - * Use self::getFromCache or DAOGetAction::getObjects + * Decide whether to use self::getFromCache or DAOGetAction::getObjects */ protected function getObjects(Result $result): void { if (is_null($this->useCache)) { @@ -62,16 +83,17 @@ protected function needDatabase(): bool { return TRUE; } - $standardFields = \Civi::entity($this->getEntityName())->getFields(); + $cachedFields = $this->getCachedFields(); + foreach ($this->select as $field) { [$field] = explode(':', $field); - if (!isset($standardFields[$field])) { + if (!isset($cachedFields[$field])) { return TRUE; } } foreach ($this->where as $clause) { [$field] = explode(':', $clause[0] ?? ''); - if (!$field || !isset($standardFields[$field])) { + if (!$field || !isset($cachedFields[$field])) { return TRUE; } // ArrayQueryTrait doesn't yet support field-to-field comparisons @@ -81,13 +103,26 @@ protected function needDatabase(): bool { } foreach ($this->orderBy as $field => $dir) { [$field] = explode(':', $field); - if (!isset($standardFields[$field])) { + if (!isset($cachedFields[$field])) { return TRUE; } } return FALSE; } + /** + * Which fields are included in the cache? + * + * By default, this is standard fields from the + * EntityRepository schema - but could be overridden + * in child classes. + * + * @return array with known fields as array *keys* + */ + protected function getCachedFields(): array { + return \Civi::entity($this->getEntityName())->getFields(); + } + /** * This works like BasicGetAction: * - provide all the records upfront from the cache @@ -100,8 +135,11 @@ protected function getFromCache($result): void { $this->queryArray($values, $result); } - protected function getCachedRecords() { - return \CRM_Core_BAO_CustomGroup::getAll(); + protected function getCachedRecords(): array { + if (is_callable($this->cacheGetter)) { + return call_user_func($this->cacheGetter, $this); + } + throw new NotImplementedException('Cache getter function not found for api4 ' . $this->getEntityName() . '::' . $this->getActionName()); } }