Reference token metadata internally
authorEileen McNaughton <emcnaughton@wikimedia.org>
Thu, 7 Oct 2021 19:30:47 +0000 (08:30 +1300)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Thu, 7 Oct 2021 22:46:47 +0000 (11:46 +1300)
This references the token metadata rather than the metadata retrieved from the api
call. Since the former is cached it should save a look up -
albeit not when prefetch is happening, at this stage

CRM/Core/EntityTokens.php
CRM/Event/Tokens.php

index 45da688677b93d17ace7deaaf921b47c12e9d07f..a61dcc59e82113ff9c9392ade81d4068e93ab984 100644 (file)
@@ -57,11 +57,11 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber {
     if (!$this->checkActive($e->getTokenProcessor())) {
       return;
     }
-    foreach ($this->getTokenMetadata() as $field) {
+    foreach ($this->getTokenMetadata() as $tokenName => $field) {
       if ($field['audience'] === 'user') {
         $e->register([
           'entity' => $this->entity,
-          'field' => $field['name'],
+          'field' => $tokenName,
           'label' => $field['title'],
         ]);
       }
@@ -83,31 +83,30 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber {
         $this->tokensMetadata = Civi::cache('metadata')->get($cacheKey);
       }
       else {
-        foreach (array_merge($this->getFieldMetadata(), $this->getBespokeTokens()) as $field) {
-          if (
-            $field['type'] === 'Custom'
-            || !empty($this->getBespokeTokens()[$field['name']])
-            || in_array($field['name'], $this->getExposedFields(), TRUE)
-          ) {
-            $field['audience'] = 'user';
-            if ($field['name'] === 'contact_id') {
-              // Since {contact.id} is almost always present don't confuse users
-              // by also adding (e.g {participant.contact_id)
-              $field['audience'] = 'sysadmin';
-            }
-            if (!empty($this->getTokenMetadataOverrides()[$field['name']])) {
-              $field = array_merge($field, $this->getTokenMetadataOverrides()[$field['name']]);
-            }
-            if ($field['type'] === 'Custom') {
-              // Convert to apiv3 style for now. Later we can add v4 with
-              // portable naming & support for labels/ dates etc so let's leave
-              // the space open for that.
-              // Not the existing quickform widget has handling for the custom field
-              // format based on the title using this syntax.
-              $field['name'] = 'custom_' . $field['custom_field_id'];
-              $parts = explode(': ', $field['label']);
-              $field['title'] = "{$parts[1]} :: {$parts[0]}";
-            }
+        $this->tokensMetadata = $this->getBespokeTokens();
+        foreach ($this->getFieldMetadata() as $field) {
+          $field['audience'] = 'user';
+          if ($field['name'] === 'contact_id') {
+            // Since {contact.id} is almost always present don't confuse users
+            // by also adding (e.g {participant.contact_id)
+            $field['audience'] = 'sysadmin';
+          }
+          if (!empty($this->getTokenMetadataOverrides()[$field['name']])) {
+            $field = array_merge($field, $this->getTokenMetadataOverrides()[$field['name']]);
+          }
+          if ($field['type'] === 'Custom') {
+            // Convert to apiv3 style for now. Later we can add v4 with
+            // portable naming & support for labels/ dates etc so let's leave
+            // the space open for that.
+            // Not the existing quickform widget has handling for the custom field
+            // format based on the title using this syntax.
+            $parts = explode(': ', $field['label']);
+            $field['title'] = "{$parts[1]} :: {$parts[0]}";
+            $tokenName = 'custom_' . $field['custom_field_id'];
+            $this->tokensMetadata[$tokenName] = $field;
+            continue;
+          }
+          if (in_array($field['name'], $this->getExposedFields(), TRUE)) {
             if (
               ($field['options'] || !empty($field['suffixes']))
               // At the time of writing currency didn't have a label option - this may have changed.
@@ -247,7 +246,7 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber {
    * @return bool
    */
   public function isBooleanField(string $fieldName): bool {
-    return $this->getFieldMetadata()[$fieldName]['data_type'] === 'Boolean';
+    return $this->getMetadataForField($fieldName)['data_type'] === 'Boolean';
   }
 
   /**
@@ -258,7 +257,7 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber {
    * @return bool
    */
   public function isDateField(string $fieldName): bool {
-    return in_array($this->getFieldMetadata()[$fieldName]['data_type'], ['Timestamp', 'Date'], TRUE);
+    return in_array($this->getMetadataForField($fieldName)['data_type'], ['Timestamp', 'Date'], TRUE);
   }
 
   /**
@@ -291,7 +290,7 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber {
    * @return bool
    */
   public function isMoneyField(string $fieldName): bool {
-    return $this->getFieldMetadata()[$fieldName]['data_type'] === 'Money';
+    return $this->getMetadataForField($fieldName)['data_type'] === 'Money';
   }
 
   /**
@@ -553,7 +552,7 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber {
    * @return string
    */
   protected function getCustomFieldName(int $id): string {
-    foreach ($this->getFieldMetadata() as $key => $field) {
+    foreach ($this->getTokenMetadata() as $key => $field) {
       if (($field['custom_field_id'] ?? NULL) === $id) {
         return $key;
       }
@@ -570,12 +569,35 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber {
    */
   protected function getCustomFieldValue($entityID, string $field) {
     $id = str_replace('custom_', '', $field);
-    $value = $this->prefetch[$entityID][$this->getCustomFieldName($id)] ?? NULL;
+    $value = $this->prefetch[$entityID][$this->getCustomFieldName($id)] ?? '';
     if ($value !== NULL) {
       return CRM_Core_BAO_CustomField::displayValue($value, $id);
     }
   }
 
+  /**
+   * Get the metadata for the field.
+   *
+   * @param string $fieldName
+   *
+   * @return array
+   */
+  protected function getMetadataForField($fieldName): array {
+    if (isset($this->getTokenMetadata()[$fieldName])) {
+      return $this->getTokenMetadata()[$fieldName];
+    }
+    return $this->getTokenMetadata()[$this->getDeprecatedTokens()[$fieldName]];
+  }
+
+  /**
+   * Get array of deprecated tokens and the new token they map to.
+   *
+   * @return array
+   */
+  protected function getDeprecatedTokens(): array {
+    return [];
+  }
+
   /**
    * Get any overrides for token metadata.
    *
index 91d5a8797b4c3bba65d49ebeacd41e33a2279c00..8c437057b1fb6d7efadb4f4f4f7b1437f6283ad3 100644 (file)
@@ -49,6 +49,7 @@ class CRM_Event_Tokens extends CRM_Core_EntityTokens {
         'type' => 'calculated',
         'options' => NULL,
         'data_type' => 'String',
+        'audience' => 'user',
       ],
       'info_url' => [
         'title' => ts('Event Info URL'),
@@ -56,6 +57,7 @@ class CRM_Event_Tokens extends CRM_Core_EntityTokens {
         'type' => 'calculated',
         'options' => NULL,
         'data_type' => 'String',
+        'audience' => 'user',
       ],
       'registration_url' => [
         'title' => ts('Event Registration URL'),
@@ -63,6 +65,7 @@ class CRM_Event_Tokens extends CRM_Core_EntityTokens {
         'type' => 'calculated',
         'options' => NULL,
         'data_type' => 'String',
+        'audience' => 'user',
       ],
       'contact_email' => [
         'title' => ts('Event Contact Email'),
@@ -70,6 +73,7 @@ class CRM_Event_Tokens extends CRM_Core_EntityTokens {
         'type' => 'calculated',
         'options' => NULL,
         'data_type' => 'String',
+        'audience' => 'user',
       ],
       'contact_phone' => [
         'title' => ts('Event Contact Phone'),
@@ -77,6 +81,7 @@ class CRM_Event_Tokens extends CRM_Core_EntityTokens {
         'type' => 'calculated',
         'options' => NULL,
         'data_type' => '',
+        'audience' => 'user',
       ],
     ];
   }
@@ -92,7 +97,7 @@ class CRM_Event_Tokens extends CRM_Core_EntityTokens {
     }
     if (array_key_exists($field, $this->getEventTokenValues($eventID))) {
       foreach ($this->getEventTokenValues($eventID)[$field] as $format => $value) {
-        $row->format($format)->tokens($entity, $field, $value);
+        $row->format($format)->tokens($entity, $field, $value ?? '');
       }
     }
   }
@@ -143,14 +148,15 @@ class CRM_Event_Tokens extends CRM_Core_EntityTokens {
       $tokens['contact_phone']['text/html'] = $event['loc_block_id.phone_id.phone'];
       $tokens['contact_email']['text/html'] = $event['loc_block_id.email_id.email'];
 
-      foreach (array_keys($this->getTokenMetadata()) as $field) {
-        if (!isset($tokens[$field])) {
-          if ($this->isCustomField($field)) {
+      foreach ($this->getTokenMetadata() as $fieldName => $fieldSpec) {
+        if (!isset($tokens[$fieldName])) {
+          if ($fieldSpec['type'] === 'Custom') {
             $this->prefetch[$eventID] = $event;
-            $tokens[$field]['text/html'] = $this->getCustomFieldValue($eventID, $field);
+            $value = $event[$fieldSpec['name']];
+            $tokens[$fieldName]['text/html'] = CRM_Core_BAO_CustomField::displayValue($value, $fieldSpec['custom_field_id']);
           }
           else {
-            $tokens[$field]['text/html'] = $event[$field];
+            $tokens[$fieldName]['text/html'] = $event[$fieldName];
           }
         }
       }