Add CRM_Utils_CacheWrapper to all caches
authorcolemanw <coleman@civicrm.org>
Sat, 2 Dec 2023 19:08:46 +0000 (19:08 +0000)
committercolemanw <coleman@civicrm.org>
Sun, 3 Dec 2023 08:20:09 +0000 (08:20 +0000)
This wraps all caches and dispatches a 'civi.cache.clear' event when deleting items from the cache.

CRM/Utils/Cache.php
CRM/Utils/Cache/CacheWrapper.php [new file with mode: 0644]
CRM/Utils/Cache/SqlGroup.php
tests/phpunit/Civi/Core/Service/AutoDefinitionTest.php

index c35c23fe7d6a2ebb93f4035ac79563cae5434522..bb4bf4560b7bef048a64ed30031cae902a4d1171 100644 (file)
@@ -168,6 +168,7 @@ class CRM_Utils_Cache {
   public static function create($params = []) {
     $types = (array) $params['type'];
 
+    // FIXME: When would name ever be empty?
     if (!empty($params['name'])) {
       $params['name'] = self::cleanKey($params['name']);
     }
@@ -183,26 +184,30 @@ class CRM_Utils_Cache {
             if (!empty($params['withArray'])) {
               $cache = $params['withArray'] === 'fast' ? new CRM_Utils_Cache_FastArrayDecorator($cache) : new CRM_Utils_Cache_ArrayDecorator($cache);
             }
-            return $cache;
+            break 2;
           }
           break;
 
         case 'SqlGroup':
           if (defined('CIVICRM_DSN') && CIVICRM_DSN) {
-            return new CRM_Utils_Cache_SqlGroup([
+            $cache = new CRM_Utils_Cache_SqlGroup([
               'group' => $params['name'],
               'prefetch' => $params['prefetch'] ?? FALSE,
             ]);
+            break 2;
           }
           break;
 
         case 'Arraycache':
         case 'ArrayCache':
-          return new CRM_Utils_Cache_ArrayCache([]);
+          $cache = new CRM_Utils_Cache_ArrayCache([]);
+          break 2;
 
       }
     }
-
+    if (isset($cache)) {
+      return new CRM_Utils_Cache_CacheWrapper($cache, $params['name'] ?? NULL);
+    }
     throw new CRM_Core_Exception("Failed to instantiate cache. No supported cache type found. " . print_r($params, 1));
   }
 
diff --git a/CRM/Utils/Cache/CacheWrapper.php b/CRM/Utils/Cache/CacheWrapper.php
new file mode 100644 (file)
index 0000000..82e7e47
--- /dev/null
@@ -0,0 +1,106 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC https://civicrm.org/licensing
+ */
+
+/**
+ */
+class CRM_Utils_Cache_CacheWrapper implements CRM_Utils_Cache_Interface {
+
+  /**
+   * @var string
+   */
+  private $cacheName;
+
+  /**
+   * @var CRM_Utils_Cache_Interface
+   */
+  private $delegate;
+
+  /**
+   * @param \CRM_Utils_Cache_Interface $delegate
+   * @param string $cacheName
+   */
+  public function __construct(\CRM_Utils_Cache_Interface $delegate, $cacheName) {
+    $this->delegate = $delegate;
+    $this->cacheName = $cacheName;
+  }
+
+  public function getMultiple($keys, $default = NULL) {
+    return $this->delegate->getMultiple($keys, $default);
+  }
+
+  public function setMultiple($values, $ttl = NULL) {
+    return $this->delegate->setMultiple($values, $ttl);
+  }
+
+  public function deleteMultiple($keys) {
+    $this->dispatchClearEvent($keys);
+    return $this->delegate->deleteMultiple($keys);
+  }
+
+  public function set($key, $value, $ttl = NULL) {
+    return $this->delegate->set($key, $value, $ttl);
+  }
+
+  public function get($key, $default = NULL) {
+    return $this->delegate->get($key, $default);
+  }
+
+  public function delete($key) {
+    $this->dispatchClearEvent([$key]);
+    return $this->delegate->delete($key);
+  }
+
+  /**
+   * @deprecated
+   */
+  public function flush() {
+    return $this->clear();
+  }
+
+  public function clear() {
+    $this->dispatchClearEvent();
+    return $this->delegate->clear();
+  }
+
+  public function has($key) {
+    return $this->delegate->has($key);
+  }
+
+  /**
+   * @param string $key
+   * @return int|null
+   */
+  public function getExpires($key) {
+    if (method_exists($this->delegate, 'getExpires')) {
+      return $this->delegate->getExpires($key);
+    }
+    return NULL;
+  }
+
+  private function dispatchClearEvent($keys = NULL) {
+    // FIXME: When would name ever be empty?
+    if ($this->cacheName) {
+      $hookParams = [
+        'cacheName' => $this->cacheName,
+        'items' => $keys,
+      ];
+      $event = \Civi\Core\Event\GenericHookEvent::create($hookParams);
+      Civi::dispatcher()->dispatch('civi.cache.clear', $event);
+    }
+  }
+
+}
index 97df20cb12745b62569389eeb68e0f375c2297f4..dbc24d8772f0f18dba7ad006c29dc07b60feb709 100644 (file)
@@ -30,7 +30,7 @@ class CRM_Utils_Cache_SqlGroup implements CRM_Utils_Cache_Interface {
   use CRM_Utils_Cache_NaiveMultipleTrait;
 
   /**
-   * The host name of the memcached server.
+   * Name of the cache group.
    *
    * @var string
    */
index 2947df817d917f14fec230dfb5a54b36e621485d..ba61ab6a1354ccb148948bead1c54afc46cdff47 100644 (file)
@@ -101,8 +101,10 @@ class AutoDefinitionTest extends \CiviUnitTestCase {
     );
 
     $instance = \Civi::service('TestNamedProperty');
-    $this->assertInstanceOf(\CRM_Utils_Cache_SqlGroup::class, $instance->cache);
-    $this->assertEquals('extension_browser', Invasive::get([$instance->cache, 'group']));
+    $this->assertInstanceOf(\CRM_Utils_Cache_CacheWrapper::class, $instance->cache);
+    $cacheClass = Invasive::get([$instance->cache, 'delegate']);
+    $this->assertInstanceOf(\CRM_Utils_Cache_SqlGroup::class, $cacheClass);
+    $this->assertEquals('extension_browser', Invasive::get([$instance->cache, 'cacheName']));
   }
 
   /**
@@ -178,8 +180,11 @@ class AutoDefinitionTest extends \CiviUnitTestCase {
 
     $instance = \Civi::service('TestInjectConstructor');
     $this->assertInstanceOf(LoggerInterface::class, Invasive::get([$instance, 'log']));
-    $this->assertInstanceOf(\CRM_Utils_Cache_SqlGroup::class, Invasive::get([$instance, 'cache']));
-    $this->assertEquals('extension_browser', Invasive::get([Invasive::get([$instance, 'cache']), 'group']));
+    $cacheWrapper = Invasive::get([$instance, 'cache']);
+    $cacheClass = Invasive::get([$cacheWrapper, 'delegate']);
+    $this->assertInstanceOf(\CRM_Utils_Cache_SqlGroup::class, $cacheClass);
+    $this->assertEquals('extension_browser', Invasive::get([$cacheWrapper, 'cacheName']));
+    $this->assertEquals('extension_browser', Invasive::get([$cacheClass, 'group']));
   }
 
   /**