Skip to content

Commit

Permalink
Merge pull request #21076 from eileenmcnaughton/camp_name
Browse files Browse the repository at this point in the history
Token Parser - Allow tokens with multiple dots (eg {contribution.contribution_recur_id.amount})
  • Loading branch information
eileenmcnaughton authored Aug 12, 2021
2 parents eab822e + 8f9e4e0 commit 6e36519
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 7 deletions.
17 changes: 10 additions & 7 deletions CRM/Utils/Token.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,16 +182,16 @@ public static function token_replace($type, $var, $value, &$str, $escapeSmarty =
}

/**
* Get< the regex for token replacement
* Get the regex for token replacement
*
* @param string $token_type
* A string indicating the the type of token to be used in the expression.
*
* @return string
* regular expression sutiable for using in preg_replace
* regular expression suitable for using in preg_replace
*/
private static function tokenRegex($token_type) {
return '/(?<!\{|\\\\)\{' . $token_type . '\.([\w]+:?\w*(\-[\w\s]+)?)\}(?!\})/';
private static function tokenRegex(string $token_type) {
return '/(?<!\{|\\\\)\{' . $token_type . '\.([\w]+(:|\.)?\w*(\-[\w\s]+)?)\}(?!\})/';
}

/**
Expand Down Expand Up @@ -1102,20 +1102,23 @@ public static function &replaceComponentTokens(&$str, $contact, $components, $es
public static function getTokens($string) {
$matches = [];
$tokens = [];
preg_match_all('/(?<!\{|\\\\)\{(\w+\.\w+:?\w*)\}(?!\})/',
preg_match_all('/(?<!\{|\\\\)\{(\w+\.\w+(:|.)?\w*)\}(?!\})/',
$string,
$matches,
PREG_PATTERN_ORDER
);

if ($matches[1]) {
foreach ($matches[1] as $token) {
[$type, $name] = preg_split('/\./', $token, 2);
$parts = explode('.', $token, 3);
$type = $parts[0];
$name = $parts[1];
$suffix = !empty($parts[2]) ? ('.' . $parts[2]) : '';
if ($name && $type) {
if (!isset($tokens[$type])) {
$tokens[$type] = [];
}
$tokens[$type][] = $name;
$tokens[$type][] = $name . $suffix;
}
}
}
Expand Down
64 changes: 64 additions & 0 deletions tests/phpunit/Civi/Token/TokenProcessorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -351,4 +351,68 @@ public function testHookTokenDiagonal() {
$this->assertTrue(isset($looped));
}

/**
* Define extended tokens with funny symbols
*/
public function testHookTokenExtraChar() {
$cid = $this->individualCreate();

$this->dispatcher->addSubscriber(new TokenCompatSubscriber());
\Civi::dispatcher()->addListener('hook_civicrm_tokens', function ($e) {
$e->tokens['food'] = [
'food.fruit.apple' => ts('Apple'),
'food.fruit:summary' => ts('Fruit summary'),
];
});
\Civi::dispatcher()->addListener('hook_civicrm_tokenValues', function ($e) {
foreach ($e->tokens['food'] ?? [] as $subtoken) {
foreach ($e->contactIDs as $cid) {
switch ($subtoken) {
case 'fruit.apple':
$e->details[$cid]['food.fruit.apple'] = 'Fruit of the Tree';
break;

case 'fruit:summary':
$e->details[$cid]['food.fruit:summary'] = 'Apples, Bananas, and Cherries Oh My';
break;
}
}
}
});

$expectRealSmartyOutputs = [
TRUE => 'Fruit of the Tree yes',
FALSE => 'Fruit of the Tree {if 1}yes{else}no{/if}',
];

$loops = 0;
foreach ([TRUE, FALSE] as $smarty) {
$p = new TokenProcessor($this->dispatcher, [
'controller' => __CLASS__,
'smarty' => $smarty,
]);
$p->addMessage('real_dot', '!!{food.fruit.apple}!!', 'text/plain');
$p->addMessage('real_dot_smarty', '{food.fruit.apple} {if 1}yes{else}no{/if}', 'text/plain');
$p->addMessage('real_colon', 'Summary of fruits: {food.fruit:summary}!', 'text/plain');
$p->addMessage('not_real_1', '!!{food.fruit}!!', 'text/plain');
$p->addMessage('not_real_2', '!!{food.apple}!!', 'text/plain');
$p->addMessage('not_real_3', '!!{fruit.apple}!!', 'text/plain');
$p->addMessage('not_real_4', '!!{food.fruit:apple}!!', 'text/plain');
$p->addRow(['contactId' => $cid]);
$p->evaluate();

foreach ($p->getRows() as $row) {
$loops++;
$this->assertEquals('!!Fruit of the Tree!!', $row->render('real_dot'));
$this->assertEquals($expectRealSmartyOutputs[$smarty], $row->render('real_dot_smarty'));
$this->assertEquals('Summary of fruits: Apples, Bananas, and Cherries Oh My!', $row->render('real_colon'));
$this->assertEquals('!!!!', $row->render('not_real_1'));
$this->assertEquals('!!!!', $row->render('not_real_2'));
$this->assertEquals('!!!!', $row->render('not_real_3'));
$this->assertEquals('!!!!', $row->render('not_real_4'));
}
}
$this->assertEquals(2, $loops);
}

}

0 comments on commit 6e36519

Please sign in to comment.