APIv4 - Cache SchemaMap in Civi::cache('metadata')
authorColeman Watts <coleman@civicrm.org>
Thu, 28 Oct 2021 19:06:46 +0000 (15:06 -0400)
committerColeman Watts <coleman@civicrm.org>
Thu, 28 Oct 2021 19:06:46 +0000 (15:06 -0400)
When adding/removing custom groups, the schema map changes.
Civi already flushes the metadata cache when this happens,
but the APIv4 SchemaMap was being cached in memory (in a container service).
This changes it to be stored in the metadata cache like everything else.

Civi/Api4/Action/Entity/GetLinks.php
Civi/Api4/Query/Api4SelectQuery.php
Civi/Api4/Utils/CoreUtil.php
Civi/Api4/services.xml

index e0458b56b59974b483dea52ddf3d4ea526548eb9..3408fea35be52113567bf5f1ca100d51a036dcf8 100644 (file)
@@ -25,8 +25,7 @@ class GetLinks extends \Civi\Api4\Generic\BasicGetAction {
   public function getRecords() {
     \CRM_Core_Error::deprecatedWarning('APIv4 Entity::getLinks is deprecated.');
     $result = [];
-    /** @var \Civi\Api4\Service\Schema\SchemaMap $schema */
-    $schema = \Civi::container()->get('schema_map');
+    $schema = CoreUtil::getSchemaMap();
     foreach ($schema->getTables() as $table) {
       $entity = CoreUtil::getApiNameFromTableName($table->getName());
       // Since this is an api function, exclude tables that don't have an api
index ff1590c32e7eacd57b25f783804fdf60339121d3..ea97c7d559bc16cacc98d26402f1fffabf5bafc1 100644 (file)
@@ -13,6 +13,7 @@ namespace Civi\Api4\Query;
 
 use Civi\API\Exception\UnauthorizedException;
 use Civi\Api4\Service\Schema\Joinable\CustomGroupJoinable;
+use Civi\Api4\Service\Schema\Joiner;
 use Civi\Api4\Utils\FormattingUtil;
 use Civi\Api4\Utils\CoreUtil;
 use Civi\Api4\Utils\SelectUtil;
@@ -1004,8 +1005,7 @@ class Api4SelectQuery {
     if (isset($this->apiFieldSpec[$key])) {
       return;
     }
-    /** @var \Civi\Api4\Service\Schema\Joiner $joiner */
-    $joiner = \Civi::container()->get('joiner');
+    $joiner = new Joiner(CoreUtil::getSchemaMap());
 
     $pathArray = explode('.', $key);
     // The last item in the path is the field name. We don't care about that; we'll add all fields from the joined entity.
index 62ee8124d9c6459f0445240b0a6144d9b5ae1387..f77607835c4dbba9b4fae5abbd134fb498b9fc87 100644 (file)
@@ -230,4 +230,17 @@ class CoreUtil {
     return static::checkAccessRecord($apiRequest, $record, $userID);
   }
 
+  /**
+   * @return \Civi\Api4\Service\Schema\SchemaMap
+   */
+  public static function getSchemaMap() {
+    $cache = \Civi::cache('metadata');
+    $schemaMap = $cache->get('api4.schema.map');
+    if (!$schemaMap) {
+      $schemaMap = \Civi::service('schema_map_builder')->build();
+      $cache->set('api4.schema.map', $schemaMap);
+    }
+    return $schemaMap;
+  }
+
 }
index 630a646326293518eebd9a87c8cefdf7b700b81e..fe1ca2efc3eaf14a432275ce7f6020465f2778ff 100644 (file)
@@ -6,18 +6,10 @@
 
         <service id="spec_gatherer" class="Civi\Api4\Service\Spec\SpecGatherer" public="true"/>
 
-        <service id="schema_map_builder" class="Civi\Api4\Service\Schema\SchemaMapBuilder" public="false">
+        <service id="schema_map_builder" class="Civi\Api4\Service\Schema\SchemaMapBuilder" public="true">
             <argument type="service" id="dispatcher" />
         </service>
 
-        <service id="schema_map" class="Civi\Api4\Service\Schema\SchemaMap" public="true">
-          <factory service="schema_map_builder" method="build"/>
-        </service>
-
-        <service id="joiner" class="Civi\Api4\Service\Schema\Joiner" public="true">
-            <argument type="service" id="schema_map"/>
-        </service>
-
         <service id="action_object_provider" class="Civi\Api4\Provider\ActionObjectProvider" public="true">
             <tag name="event_subscriber"/>
         </service>