Switch replaceGreetingTokens over
authorEileen McNaughton <emcnaughton@wikimedia.org>
Mon, 11 Oct 2021 06:56:11 +0000 (19:56 +1300)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Sat, 23 Oct 2021 00:13:15 +0000 (13:13 +1300)
CRM/Contact/Tokens.php
CRM/Utils/Token.php

index 7df4720e9368443dcebc452104b9877bf85771c3..6fa88a07591b74a5f6ddb89f3ecd89fb5ba2085a 100644 (file)
@@ -288,8 +288,8 @@ class CRM_Contact_Tokens extends CRM_Core_EntityTokens {
    * @throws \CRM_Core_Exception
    */
   public function onEvaluate(TokenValueEvent $e) {
-    $messageTokens = $e->getTokenProcessor()->getMessageTokens()['contact'] ?? [];
-    if (empty($messageTokens)) {
+    $this->activeTokens = $e->getTokenProcessor()->getMessageTokens()['contact'] ?? [];
+    if (empty($this->activeTokens)) {
       return;
     }
 
@@ -302,10 +302,10 @@ class CRM_Contact_Tokens extends CRM_Core_EntityTokens {
       $swapLocale = empty($row->context['locale']) ? NULL : \CRM_Utils_AutoClean::swapLocale($row->context['locale']);
 
       if (empty($row->context['contact'])) {
-        $row->context['contact'] = $this->getContact($row->context['contactId'], $messageTokens);
+        $row->context['contact'] = $this->getContact($row->context['contactId'], $this->activeTokens);
       }
 
-      foreach ($messageTokens as $token) {
+      foreach ($this->activeTokens as $token) {
         if ($token === 'checksum') {
           $cs = \CRM_Contact_BAO_Contact_Utils::generateChecksum($row->context['contactId'],
             NULL,
@@ -351,6 +351,13 @@ class CRM_Contact_Tokens extends CRM_Core_EntityTokens {
         return $row->context[$entityName][$possibility];
       }
     }
+    $contactID = $this->getFieldValue($row, 'id');
+    if ($contactID) {
+      $row->context['contact'] = array_merge($this->getContact($contactID, $this->activeTokens), $row->context['contact']);
+      if (isset($row->context[$entityName][$field])) {
+        return $row->context[$entityName][$field];
+      }
+    }
     return '';
   }
 
@@ -446,6 +453,11 @@ class CRM_Contact_Tokens extends CRM_Core_EntityTokens {
         ($joinEntity !== 'Website' ? [$alias . '.is_primary', '=', 1] : []));
     }
     $contact = $contactApi->execute()->first();
+    if (!$contact) {
+      // This is probably a test-only situation where tokens are retrieved for a
+      // fake contact id - check `testReplaceGreetingTokens`
+      return [];
+    }
 
     foreach ($this->getDeprecatedTokens() as $apiv3Name => $fieldName) {
       // it would be set already with the right value for a greeting token
@@ -678,6 +690,15 @@ class CRM_Contact_Tokens extends CRM_Core_EntityTokens {
         'data_type' => 'String',
         'audience' => 'sysadmin',
       ],
+      // this gets forced out if we specify individual fields
+      'household_name' => [
+        'title' => ts('Household name'),
+        'name' => 'household_name',
+        'type' => 'Field',
+        'options' => NULL,
+        'data_type' => 'String',
+        'audience' => 'sysadmin',
+      ],
     ];
   }
 
index 421e7cefc16ef10c7294e055473e71e6e13491c2..2f7db99438a6cce9607fb17f10eb609d24cce330 100644 (file)
@@ -9,6 +9,8 @@
  +--------------------------------------------------------------------+
  */
 
+use Civi\Token\TokenProcessor;
+
 /**
  *
  * @package CRM
@@ -592,6 +594,8 @@ class CRM_Utils_Token {
    * @param bool $returnBlankToken
    *   Return unevaluated token if value is null.
    *
+   * @deprecated
+   *
    * @param bool $escapeSmarty
    *
    * @return string
@@ -634,6 +638,13 @@ class CRM_Utils_Token {
   }
 
   /**
+   * Do Not use.
+   *
+   * Only core usage is from a deprecated unused function and
+   * from deprecated BAO_Mailing code (to be replaced by flexmailer).
+   *
+   * @deprecated
+   *
    * @param $token
    * @param $contact
    * @param bool $html
@@ -718,9 +729,13 @@ class CRM_Utils_Token {
   }
 
   /**
+   * Do not use - unused in core.
+   *
    * Replace all the hook tokens in $str with information from
    * $contact.
    *
+   * @deprecated
+   *
    * @param string $str
    *   The string with tokens to be replaced.
    * @param array $contact
@@ -790,6 +805,10 @@ class CRM_Utils_Token {
   }
 
   /**
+   * Do not use, unused in core.
+   *
+   * @deprecated
+   *
    * @param $token
    * @param $contact
    * @param $category
@@ -1303,9 +1322,6 @@ class CRM_Utils_Token {
    *
    * @TODO Remove that inconsistency in usage.
    *
-   * ::replaceContactTokens() may need to be called after this method, to
-   * replace tokens supplied from this method.
-   *
    * @param string $tokenString
    * @param array $contactDetails
    * @param int $contactId
@@ -1317,73 +1333,25 @@ class CRM_Utils_Token {
     if (!$contactDetails && !$contactId) {
       return;
     }
-
     // check if there are any tokens
     $greetingTokens = self::getTokens($tokenString);
-
-    if (!empty($greetingTokens)) {
-      // first use the existing contact object for token replacement
-      if (!empty($contactDetails)) {
-        $tokenString = CRM_Utils_Token::replaceContactTokens($tokenString, $contactDetails, TRUE, $greetingTokens, TRUE, $escapeSmarty);
-      }
-
-      self::removeNullContactTokens($tokenString, $contactDetails, $greetingTokens);
-      // check if there are any unevaluated tokens
-      $greetingTokens = self::getTokens($tokenString);
-
-      // $greetingTokens not empty, means there are few tokens which are not
-      // evaluated, like custom data etc
-      // so retrieve it from database
-      if (!empty($greetingTokens) && array_key_exists('contact', $greetingTokens)) {
-        $greetingsReturnProperties = array_flip(CRM_Utils_Array::value('contact', $greetingTokens));
-        $greetingsReturnProperties = array_fill_keys(array_keys($greetingsReturnProperties), 1);
-        $contactParams = ['contact_id' => $contactId];
-
-        $greetingDetails = self::getTokenDetails($contactParams,
-          $greetingsReturnProperties,
-          FALSE, FALSE, NULL,
-          $greetingTokens,
-          $className
-        );
-
-        // again replace tokens
-        $tokenString = CRM_Utils_Token::replaceContactTokens($tokenString,
-          $greetingDetails,
-          TRUE,
-          $greetingTokens,
-          TRUE,
-          $escapeSmarty
-        );
-      }
-
-      // check if there are still any unevaluated tokens
-      $remainingTokens = self::getTokens($tokenString);
-
-      // $greetingTokens not empty, there are customized or hook tokens to replace
-      if (!empty($remainingTokens)) {
-        // Fill the return properties array
-        $greetingTokens = $remainingTokens;
-        reset($greetingTokens);
-        $greetingsReturnProperties = [];
-        foreach ($greetingTokens as $value) {
-          $props = array_flip($value);
-          $props = array_fill_keys(array_keys($props), 1);
-          $greetingsReturnProperties = $greetingsReturnProperties + $props;
-        }
-        $contactParams = ['contact_id' => $contactId];
-        $greetingDetails = self::getTokenDetails($contactParams,
-          $greetingsReturnProperties,
-          FALSE, FALSE, NULL,
-          $greetingTokens,
-          $className
-        );
-        // Prepare variables for calling replaceHookTokens
-        $categories = array_keys($greetingTokens);
-        [$contact] = $greetingDetails;
-        // Replace tokens defined in Hooks.
-        $tokenString = CRM_Utils_Token::replaceHookTokens($tokenString, $contact[$contactId], $categories);
+    $context = $contactId ? ['contactId' => $contactId] : [];
+    if ($contactDetails) {
+      foreach ($contactDetails[0] as $contact) {
+        // Only 1 - the loop is because we may not know the id.
+        $context['contact'] = $contact;
       }
     }
+    $tokenProcessor = new TokenProcessor(\Civi::dispatcher(), [
+      'smarty' => FALSE,
+      'class' => $className,
+    ]);
+    $tokenProcessor->addRow($context);
+    $tokenProcessor->addMessage('greeting', $tokenString, 'text/plain');
+    $tokenProcessor->evaluate();
+    foreach ($tokenProcessor->getRows() as $row) {
+      $tokenString = $row->render('greeting');
+    }
   }
 
   /**
@@ -1391,6 +1359,8 @@ class CRM_Utils_Token {
    * (non-custom) missing fields are null.  By removing them, we can avoid
    * expensive calls to CRM_Contact_BAO_Query.
    *
+   * @deprecated unused in core
+   *
    * @param string $tokenString
    * @param array $contactDetails
    * @param array $greetingTokens
@@ -1862,6 +1832,10 @@ class CRM_Utils_Token {
   }
 
   /**
+   * @deprecated
+   *
+   * Only used from deprecated functions not called by core.
+   *
    * @return array
    *   [legacy_token => new_token]
    */