Fix token deprecation to be a check not an upgrade notice
[civicrm-core.git] / CRM / Utils / Token.php
index e41a872038ebe49cc440d3d199282b7e8077c620..67f3137c8ae1eb54ff336c348f9bd4447ada8b75 100644 (file)
@@ -191,7 +191,7 @@ class CRM_Utils_Token {
    *   regular expression sutiable for using in preg_replace
    */
   private static function tokenRegex($token_type) {
-    return '/(?<!\{|\\\\)\{' . $token_type . '\.([\w]+(\-[\w\s]+)?)\}(?!\})/';
+    return '/(?<!\{|\\\\)\{' . $token_type . '\.([\w]+:?\w*(\-[\w\s]+)?)\}(?!\})/';
   }
 
   /**
@@ -313,10 +313,20 @@ class CRM_Utils_Token {
   /**
    * Replace all the org-level tokens in $str
    *
-   * @fixme: This function appears to be broken, as it depends on
+   * @fixme: This function appears to be broken, as it depended on
    * nonexistant method: CRM_Core_BAO_CustomValue::getContactValues()
-   * Marking as deprecated until this is fixed
+   * Marking as deprecated until this is clarified.
+   *
    * @deprecated
+   *  - the above hard-breakage was there from 2015 to 2021 and
+   * no error was ever reported on it -does that mean
+   * 1) the code is never hit because the only function that
+   * calls this function is never called or
+   * 2) it was called but never required to resolve any tokens
+   * or more specifically custom field tokens
+   *
+   * The handling for custom fields with the removed token has
+   * now been removed.
    *
    * @param string $str
    *   The string with tokens to be replaced.
@@ -330,17 +340,16 @@ class CRM_Utils_Token {
    * @return string
    *   The processed string
    */
-  public static function &replaceOrgTokens($str, &$org, $html = FALSE, $escapeSmarty = FALSE) {
+  public static function replaceOrgTokens($str, &$org, $html = FALSE, $escapeSmarty = FALSE) {
     self::$_tokens['org']
       = array_merge(
         array_keys(CRM_Contact_BAO_Contact::importableFields('Organization')),
         ['address', 'display_name', 'checksum', 'contact_id']
       );
 
-    $cv = NULL;
     foreach (self::$_tokens['org'] as $token) {
       // print "Getting token value for $token<br/><br/>";
-      if ($token == '') {
+      if ($token === '') {
         continue;
       }
 
@@ -354,23 +363,11 @@ class CRM_Utils_Token {
 
       $value = NULL;
 
-      if ($cfID = CRM_Core_BAO_CustomField::getKeyID($token)) {
-        // only generate cv if we need it
-        if ($cv === NULL) {
-          $cv = CRM_Core_BAO_CustomValue::getContactValues($org['contact_id']);
-        }
-        foreach ($cv as $cvFieldID => $value) {
-          if ($cvFieldID == $cfID) {
-            $value = CRM_Core_BAO_CustomField::displayValue($value, $cfID);
-            break;
-          }
-        }
-      }
-      elseif ($token == 'checksum') {
+      if ($token === 'checksum') {
         $cs = CRM_Contact_BAO_Contact_Utils::generateChecksum($org['contact_id']);
         $value = "cs={$cs}";
       }
-      elseif ($token == 'address') {
+      elseif ($token === 'address') {
         // Build the location values array
 
         $loc = [];
@@ -732,22 +729,12 @@ class CRM_Utils_Token {
       $value = "cs={$cs}";
     }
     else {
-      $value = CRM_Utils_Array::retrieveValueRecursive($contact, $token);
+      $value = (array) CRM_Utils_Array::retrieveValueRecursive($contact, $token);
 
-      // FIXME: for some pseudoconstants we get array ( 0 => id, 1 => label )
-      if (is_array($value)) {
-        $value = $value[1];
-      }
-      // Convert pseudoconstants using metadata
-      elseif ($value && is_numeric($value)) {
-        $allFields = CRM_Contact_BAO_Contact::exportableFields('All');
-        if (!empty($allFields[$token]['pseudoconstant'])) {
-          $value = CRM_Core_PseudoConstant::getLabel('CRM_Contact_BAO_Contact', $token, $value);
-        }
-      }
-      elseif ($value && CRM_Utils_String::endsWith($token, '_date')) {
-        $value = CRM_Utils_Date::customFormat($value);
+      foreach ($value as $index => $item) {
+        $value[$index] = self::convertPseudoConstantsUsingMetadata($value[$index], $token);
       }
+      $value = implode(', ', $value);
     }
 
     if (!$html) {
@@ -794,10 +781,13 @@ class CRM_Utils_Token {
   public static function &replaceHookTokens(
     $str,
     &$contact,
-    &$categories,
+    $categories = NULL,
     $html = FALSE,
     $escapeSmarty = FALSE
   ) {
+    if (!$categories) {
+      $categories = self::getTokenCategories();
+    }
     foreach ($categories as $key) {
       $str = preg_replace_callback(
         self::tokenRegex($key),
@@ -810,6 +800,20 @@ class CRM_Utils_Token {
     return $str;
   }
 
+  /**
+   * Get the categories required for rendering tokens.
+   *
+   * @return array
+   */
+  public static function getTokenCategories(): array {
+    if (!isset(\Civi::$statics[__CLASS__]['token_categories'])) {
+      $tokens = [];
+      \CRM_Utils_Hook::tokens($tokens);
+      \Civi::$statics[__CLASS__]['token_categories'] = array_keys($tokens);
+    }
+    return \Civi::$statics[__CLASS__]['token_categories'];
+  }
+
   /**
    * Parse html through Smarty resolving any smarty functions.
    * @param string $tokenHtml
@@ -1098,7 +1102,7 @@ class CRM_Utils_Token {
   public static function getTokens($string) {
     $matches = [];
     $tokens = [];
-    preg_match_all('/(?<!\{|\\\\)\{(\w+\.\w+)\}(?!\})/',
+    preg_match_all('/(?<!\{|\\\\)\{(\w+\.\w+:?\w*)\}(?!\})/',
       $string,
       $matches,
       PREG_PATTERN_ORDER
@@ -1554,12 +1558,22 @@ class CRM_Utils_Token {
 
   protected static function _buildContributionTokens() {
     $key = 'contribution';
-    if (self::$_tokens[$key] == NULL) {
-      self::$_tokens[$key] = array_keys(array_merge(CRM_Contribute_BAO_Contribution::exportableFields('All'),
-        ['campaign', 'financial_type'],
-        self::getCustomFieldTokens('Contribution')
-      ));
+
+    if (!isset(Civi::$statics[__CLASS__][__FUNCTION__][$key])) {
+      $processor = new CRM_Contribute_Tokens();
+      $tokens = array_merge(CRM_Contribute_BAO_Contribution::exportableFields('All'),
+        ['campaign' => [], 'financial_type' => [], 'payment_instrument' => []],
+        self::getCustomFieldTokens('Contribution'),
+        $processor->getPseudoTokens()
+      );
+      foreach ($tokens as $token) {
+        if (!empty($token['name'])) {
+          $tokens[$token['name']] = [];
+        }
+      }
+      Civi::$statics[__CLASS__][__FUNCTION__][$key] = array_keys($tokens);
     }
+    self::$_tokens[$key] = Civi::$statics[__CLASS__][__FUNCTION__][$key];
   }
 
   /**
@@ -1676,7 +1690,6 @@ class CRM_Utils_Token {
       //early return
       return $str;
     }
-    self::_buildContributionTokens();
 
     // here we intersect with the list of pre-configured valid tokens
     // so that we remove anything we do not recognize
@@ -1897,4 +1910,39 @@ class CRM_Utils_Token {
     return $output;
   }
 
+  /**
+   * @param $value
+   * @param $token
+   *
+   * @return bool|int|mixed|string|null
+   */
+  protected static function convertPseudoConstantsUsingMetadata($value, $token) {
+    // Convert pseudoconstants using metadata
+    if ($value && is_numeric($value)) {
+      $allFields = CRM_Contact_BAO_Contact::exportableFields('All');
+      if (!empty($allFields[$token]['pseudoconstant'])) {
+        $value = CRM_Core_PseudoConstant::getLabel('CRM_Contact_BAO_Contact', $token, $value);
+      }
+    }
+    elseif ($value && CRM_Utils_String::endsWith($token, '_date')) {
+      $value = CRM_Utils_Date::customFormat($value);
+    }
+    return $value;
+  }
+
+  /**
+   * Get token deprecation information.
+   *
+   * @return array
+   */
+  public static function getTokenDeprecations(): array {
+    return [
+      'WorkFlowMessageTemplates' => [
+        'contribution_invoice_receipt' => [
+          '$display_name' => 'contact.display_name',
+        ],
+      ],
+    ];
+  }
+
 }