From: Tim Otten Date: Fri, 3 Mar 2023 09:38:29 +0000 (-0800) Subject: Tokens - "|upper" and "|lower" should work differently in text+html X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=2b50e59bc0cc0b32f233c4a03107fab557a50797;p=civicrm-core.git Tokens - "|upper" and "|lower" should work differently in text+html --- diff --git a/Civi/Token/StandardFilters.php b/Civi/Token/StandardFilters.php index 69f1b86783..54c4f3996e 100644 --- a/Civi/Token/StandardFilters.php +++ b/Civi/Token/StandardFilters.php @@ -24,11 +24,29 @@ class StandardFilters { * @return mixed */ public static function upper($value, array $filter, string $format) { - return mb_strtoupper($value); + switch ($format) { + case 'text/plain': + return mb_strtoupper($value); + + case 'text/html': + return \CRM_Utils_XML::filterMarkupText((string) $value, 'mb_strtoupper'); + + default: + throw new \CRM_Core_Exception(sprintf('Filter %s does not support format %s', __FUNCTION__, $format)); + } } public static function lower($value, array $filter, string $format) { - return mb_strtolower($value); + switch ($format) { + case 'text/plain': + return mb_strtolower($value); + + case 'text/html': + return \CRM_Utils_XML::filterMarkupText((string) $value, 'mb_strtolower'); + + default: + throw new \CRM_Core_Exception(sprintf('Filter %s does not support format %s', __FUNCTION__, $format)); + } } public static function boolean($value, array $filter, string $format) { diff --git a/tests/phpunit/Civi/Token/TokenProcessorTest.php b/tests/phpunit/Civi/Token/TokenProcessorTest.php index ba90ef4fb8..053e50a814 100644 --- a/tests/phpunit/Civi/Token/TokenProcessorTest.php +++ b/tests/phpunit/Civi/Token/TokenProcessorTest.php @@ -384,20 +384,79 @@ class TokenProcessorTest extends \CiviUnitTestCase { $this->assertEquals(1, $this->counts['onEvalTokens']); } - public function testFilter(): void { - $exampleTokens['foo_bar']['whiz_bang'] = 'Some Text'; - $exampleTokens['foo_bar']['whiz_bop'] = ''; - $exampleMessages = [ - 'This is {foo_bar.whiz_bang}.' => 'This is Some Text.', - 'This is {foo_bar.whiz_bang|lower}...' => 'This is some text...', - 'This is {foo_bar.whiz_bang|upper}!' => 'This is SOME TEXT!', - 'This is {foo_bar.whiz_bang|boolean}!' => 'This is 1!', - 'This is {foo_bar.whiz_bop|boolean}!' => 'This is 0!', - 'This is {foo_bar.whiz_bang|default:"bang"}.' => 'This is Some Text.', - 'This is {foo_bar.whiz_bop|default:"bop"}.' => 'This is bop.', + public function getFilterExamples() { + $exampleTokens = [ + // All the "{my_text.*}" tokens will be treated as plain-text ("text/plain"). + 'my_text' => [ + 'whiz_bang' => 'Some Text', + 'empty_string' => '', + 'emotive' => 'The Test :>', + ], + // All the "{my_rich_text.*}" tokens will be treated as markup ("text/html"). + 'my_rich_text' => [ + 'whiz_bang' => 'Some “Text”', + 'empty_string' => '', + 'and_such' => 'testing & such', + ], + ]; + + $testCases = []; + $testCases['TextMessages with TextData'] = [ + 'text/plain', + [ + 'This is {my_text.whiz_bang}.' => 'This is Some Text.', + 'This is {my_text.whiz_bang|lower}...' => 'This is some text...', + 'This is {my_text.whiz_bang|upper}!' => 'This is SOME TEXT!', + 'This is {my_text.whiz_bang|boolean}!' => 'This is 1!', + 'This is {my_text.empty_string|boolean}!' => 'This is 0!', + 'This is {my_text.whiz_bang|default:"bang"}.' => 'This is Some Text.', + 'This is {my_text.empty_string|default:"bop"}.' => 'This is bop.', + ], + $exampleTokens, + ]; + $testCases['HtmlMessages with HtmlData'] = [ + 'text/html', + [ + 'This is {my_rich_text.whiz_bang}.' => 'This is Some “Text”.', + 'This is {my_rich_text.whiz_bang|lower}...' => 'This is some “text”...', + 'This is {my_rich_text.whiz_bang|upper}!' => 'This is SOME “TEXT”!', + 'This is {my_rich_text.whiz_bang|boolean}!' => 'This is 1!', + 'This is {my_rich_text.empty_string|boolean}!' => 'This is 0!', + 'This is {my_rich_text.whiz_bang|default:"bang"}.' => 'This is Some “Text”.', + 'This is {my_rich_text.empty_string|default:"bop"}.' => 'This is bop.', + ], + $exampleTokens, ]; - // We expect 7 messages to be parsed 2 times each - ie 14 times. - $expectExampleCount = 14; + $testCases['HtmlMessages with TextData'] = [ + 'text/html', + [ + 'This is {my_text.emotive}...' => 'This is The Test :>...', + 'This is {my_text.emotive|lower}...' => 'This is the test :>...', + 'This is {my_text.emotive|upper}!' => 'This is THE TEST :>!', + ], + $exampleTokens, + ]; + $testCases['TextMessages with HtmlData'] = [ + 'text/plain', + [ + 'This is {my_rich_text.and_such}...' => 'This is testing & such...', + 'This is {my_rich_text.and_such|lower}...' => 'This is testing & such...', + 'This is {my_rich_text.and_such|upper}!' => 'This is TESTING & SUCH!', + ], + $exampleTokens, + ]; + return $testCases; + } + + /** + * @param string $messageFormat + * @param array $exampleMessages + * @param array $exampleTokens + * @return void + * @dataProvider getFilterExamples + */ + public function testFilters(string $messageFormat, array $exampleMessages, array $exampleTokens): void { + $expectExampleCount = 2 * count($exampleMessages); $actualExampleCount = 0; foreach ($exampleMessages as $inputMessage => $expectOutput) { @@ -406,9 +465,10 @@ class TokenProcessorTest extends \CiviUnitTestCase { 'controller' => __CLASS__, 'smarty' => $useSmarty, ]); - $p->addMessage('example', $inputMessage, 'text/plain'); + $p->addMessage('example', $inputMessage, $messageFormat); $p->addRow() - ->format('text/plain')->tokens($exampleTokens); + ->format('text/plain')->tokens(\CRM_Utils_Array::subset($exampleTokens, ['my_text'])) + ->format('text/html')->tokens(\CRM_Utils_Array::subset($exampleTokens, ['my_rich_text'])); foreach ($p->evaluate()->getRows() as $row) { $this->assertEquals($expectOutput, $row->render('example')); $actualExampleCount++;