dev/core#2814 fix tokenCompat to be consistent with unresolved tokens
authorEileen McNaughton <emcnaughton@wikimedia.org>
Wed, 22 Sep 2021 06:18:31 +0000 (18:18 +1200)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Wed, 22 Sep 2021 22:35:44 +0000 (10:35 +1200)
This fixes the tokenCompat subscriber to replace unresolved tokens with a
blank string in a consistent way.

Prior to this it would crash if smarty was enabled but not all tokens
were resolved & print unresolved tokens if smarty was not enabled.

The inconsistencies appear to be due to 'separate evolution' rather than '*reasons*'

Civi/Token/TokenCompatSubscriber.php
tests/phpunit/CRM/Activity/Form/Task/PDFLetterCommonTest.php
tests/phpunit/CRM/Core/BAO/MessageTemplateTest.php

index 92e20b780680f0d3c9ad2a39cca84cf1a9a4bb96..bef111009a227aec508d6cfcea0671baaa798315 100644 (file)
@@ -411,21 +411,18 @@ class TokenCompatSubscriber implements EventSubscriberInterface {
    * Apply the various CRM_Utils_Token helpers.
    *
    * @param \Civi\Token\Event\TokenRenderEvent $e
-   *
-   * @throws \CRM_Core_Exception
    */
   public function onRender(TokenRenderEvent $e): void {
-    $isHtml = ($e->message['format'] === 'text/html');
     $useSmarty = !empty($e->context['smarty']);
-
-    if (!empty($e->context['contact'])) {
-      // @todo - remove this - it simply removes the last unresolved tokens before
-      // they break smarty.
-      // historically it was only called when context['contact'] so that is
-      // retained but it only works because it's almost always true.
-      $remainingTokens = array_keys(\CRM_Utils_Token::getTokens($e->string));
-      if (!empty($remainingTokens)) {
-        $e->string = \CRM_Utils_Token::replaceHookTokens($e->string, $e->context['contact'], $remainingTokens);
+    $remainingTokens = \CRM_Utils_Token::getTokens($e->string);
+
+    if ($remainingTokens) {
+      foreach ($remainingTokens as $part1 => $part2) {
+        $e->string = preg_replace(
+          '/(?<!\{|\\\\)\{' . $part1 . '\.([\w]+(:|\.)?\w*(\-[\w\s]+)?)\}(?!\})/',
+          '',
+          $e->string
+        );
       }
     }
 
index 4e920f45f53914ddda189818bae2f9afaa2990b8..97c07607974f126e8560dcbbc93a377adf49d6ec 100644 (file)
@@ -140,15 +140,16 @@ class CRM_Activity_Form_Task_PDFLetterCommonTest extends CiviUnitTestCase {
   }
 
   /**
+   * Unknown tokens are removed at the very end.
+   *
    * @throws \CRM_Core_Exception
    * @throws \CiviCRM_API3_Exception
    */
   public function testCreateDocumentUnknownTokens(): void {
     $activity = $this->activityCreate();
-    $html_message = 'Unknown token: {activity.something_unknown}';
+    $html_message = 'Unknown token: ';
     $form = $this->getFormObject('CRM_Activity_Form_Task_PDF');
     $output = $form->createDocument([$activity['id']], $html_message, ['is_unit_test' => TRUE]);
-    // Unknown tokens should be left alone
     $this->assertEquals($html_message, $output[0]);
   }
 
index ed303f27341fbef855367105c481ad6838aec3fc..3b5454cb66049fa0b11c29deba5ba5a29062e635 100644 (file)
@@ -397,6 +397,20 @@ emo
     }
   }
 
+  /**
+   * Test that unresolved tokens are not causing a fatal error in smarty.
+   *
+   * @throws \API_Exception
+   * @throws \CRM_Core_Exception
+   */
+  public function testUnresolvedTokens(): void {
+    CRM_Core_BAO_MessageTemplate::renderTemplate([
+      'messageTemplate' => [
+        'msg_text' => '{contact.blah}',
+      ],
+    ])['text'];
+  }
+
   /**
    * Hook to advertise tokens.
    *