APIv4 - Store entity info in metadata cache
authorColeman Watts <coleman@civicrm.org>
Thu, 24 Jun 2021 20:09:33 +0000 (16:09 -0400)
committerColeman Watts <coleman@civicrm.org>
Fri, 25 Jun 2021 02:00:17 +0000 (22:00 -0400)
Note that this caches the info returned by the generic function in
`AbstractEntity::getInfo()` and some entities override that function.
However the overrides generally call the parent and do not perform any expensive
computations of their own, so this seems like the best spot to add caching.

Civi/Api4/Generic/AbstractEntity.php

index 5dec8467b891511f4bddce8aec005b5a0a701f9c..1e17d1337f585bbc2afc9c9c6bb05b621af859c0 100644 (file)
@@ -132,35 +132,41 @@ abstract class AbstractEntity {
    * @return array
    */
   public static function getInfo() {
-    $info = [
-      'name' => static::getEntityName(),
-      'title' => static::getEntityTitle(),
-      'title_plural' => static::getEntityTitle(TRUE),
-      'type' => [self::stripNamespace(get_parent_class(static::class))],
-      'paths' => static::getEntityPaths(),
-      'class' => static::class,
-      'id_field' => 'id',
-      // Entities without a @searchable annotation will default to secondary,
-      // which makes them visible in SearchKit but not at the top of the list.
-      'searchable' => 'secondary',
-    ];
-    // Add info for entities with a corresponding DAO
-    $dao = \CRM_Core_DAO_AllCoreTables::getFullName($info['name']);
-    if ($dao) {
-      $info['paths'] = $dao::getEntityPaths();
-      $info['icon'] = $dao::$_icon;
-      $info['label_field'] = $dao::$_labelField;
-      $info['dao'] = $dao;
-    }
-    foreach (ReflectionUtils::getTraits(static::class) as $trait) {
-      $info['type'][] = self::stripNamespace($trait);
-    }
-    $reflection = new \ReflectionClass(static::class);
-    $info = array_merge($info, ReflectionUtils::getCodeDocs($reflection, NULL, ['entity' => $info['name']]));
-    if ($dao) {
-      $info['description'] = $dao::getEntityDescription() ?? $info['description'] ?? NULL;
+    $cache = \Civi::cache('metadata');
+    $entityName = static::getEntityName();
+    $info = $cache->get("api4.$entityName.info");
+    if (!$info) {
+      $info = [
+        'name' => $entityName,
+        'title' => static::getEntityTitle(),
+        'title_plural' => static::getEntityTitle(TRUE),
+        'type' => [self::stripNamespace(get_parent_class(static::class))],
+        'paths' => static::getEntityPaths(),
+        'class' => static::class,
+        'id_field' => 'id',
+        // Entities without a @searchable annotation will default to secondary,
+        // which makes them visible in SearchKit but not at the top of the list.
+        'searchable' => 'secondary',
+      ];
+      // Add info for entities with a corresponding DAO
+      $dao = \CRM_Core_DAO_AllCoreTables::getFullName($info['name']);
+      if ($dao) {
+        $info['paths'] = $dao::getEntityPaths();
+        $info['icon'] = $dao::$_icon;
+        $info['label_field'] = $dao::$_labelField;
+        $info['dao'] = $dao;
+      }
+      foreach (ReflectionUtils::getTraits(static::class) as $trait) {
+        $info['type'][] = self::stripNamespace($trait);
+      }
+      $reflection = new \ReflectionClass(static::class);
+      $info = array_merge($info, ReflectionUtils::getCodeDocs($reflection, NULL, ['entity' => $info['name']]));
+      if ($dao) {
+        $info['description'] = $dao::getEntityDescription() ?? $info['description'] ?? NULL;
+      }
+      unset($info['package'], $info['method']);
+      $cache->set("api4.$entityName.info", $info);
     }
-    unset($info['package'], $info['method']);
     return $info;
   }