return [
'civi.token.eval' => [
['setupSmartyAliases', 1000],
+ ['evaluateLegacyHookTokens', 500],
['onEvaluate'],
],
'civi.token.render' => 'onRender',
$proc->addMessage('TokenCompatSubscriber.aliases', $fakeMessage, 'text/plain');
}
+ /**
+ * Load token data from legacy hooks.
+ *
+ * While our goal is for people to move towards implementing
+ * toke processors the old-style hooks can extend contact
+ * token data.
+ *
+ * When that is happening we need to load the full contact record
+ * to send to the hooks (not great for performance but the
+ * fix is to move away from implementing legacy style hooks).
+ *
+ * Consistent with prior behaviour we only load the contact it it
+ * is already loaded. In that scenario we also load any extra fields
+ * that might be wanted for the contact tokens.
+ *
+ * @param \Civi\Token\Event\TokenValueEvent $e
+ * @throws TokenException
+ */
+ public function evaluateLegacyHookTokens(TokenValueEvent $e): void {
+ $messageTokens = $e->getTokenProcessor()->getMessageTokens();
+ $hookTokens = array_intersect(\CRM_Utils_Token::getTokenCategories(), array_keys($messageTokens));
+ if (empty($hookTokens)) {
+ return;
+ }
+ foreach ($e->getRows() as $row) {
+ if (empty($row->context['contactId'])) {
+ continue;
+ }
+ unset($swapLocale);
+ $swapLocale = empty($row->context['locale']) ? NULL : \CRM_Utils_AutoClean::swapLocale($row->context['locale']);
+ if (empty($row->context['contact'])) {
+ // If we don't have the contact already load it now, getting full
+ // details for hooks and anything the contact token resolution might
+ // want later.
+ $row->context['contact'] = $this->getContact($row->context['contactId'], $messageTokens['contact'] ?? [], TRUE);
+ }
+ $contactArray = [$row->context['contactId'] => $row->context['contact']];
+ \CRM_Utils_Hook::tokenValues($contactArray,
+ [$row->context['contactId']],
+ empty($row->context['mailingJobId']) ? NULL : $row->context['mailingJobId'],
+ $messageTokens,
+ $row->context['controller']
+ );
+ foreach ($hookTokens as $hookToken) {
+ foreach ($messageTokens[$hookToken] as $tokenName) {
+ $row->format('text/plain')->tokens($hookToken, $tokenName, $contactArray[$row->context['contactId']][$tokenName] ?? '');
+ }
+ }
+ }
+ }
+
/**
* Load token data.
*
$e->getTokenProcessor()->context['hookTokenCategories'] = \CRM_Utils_Token::getTokenCategories();
- $messageTokens = $e->getTokenProcessor()->getMessageTokens();
+ $messageTokens = $e->getTokenProcessor()->getMessageTokens()['contact'] ?? [];
foreach ($e->getRows() as $row) {
if (empty($row->context['contactId'])) {
/** @var int $contactId */
$contactId = $row->context['contactId'];
if (empty($row->context['contact'])) {
- $contact = $this->getContact($contactId, $messageTokens['contact'] ?? [], TRUE);
+ $contact = $this->getContact($contactId, $messageTokens);
}
else {
$contact = $row->context['contact'];
}
-
- $contactArray = [$contactId => $contact];
- \CRM_Utils_Hook::tokenValues($contactArray,
- [$contactId],
- empty($row->context['mailingJobId']) ? NULL : $row->context['mailingJobId'],
- $messageTokens,
- $row->context['controller']
- );
-
- // merge the custom tokens in the $contact array
- if (!empty($contactArray[$contactId])) {
- $contact = array_merge($contact, $contactArray[$contactId]);
- }
$row->context('contact', $contact);
}
}
// work in combination.
$tokenString = '{$pre_assigned_smarty}{$passed_smarty}
{domain.name}
+{important_stuff.favourite_emoticon}
';
foreach (array_keys($tokenData) as $key) {
$tokenString .= "{$key}:{contact.{$key}}\n";
]);
$expected = 'weewhoa
Default Domain Name
+emo
';
$expected .= $this->getExpectedContactOutput($address['id'], $tokenData, $messageContent['html']);
$this->assertEquals($expected, $messageContent['html']);
];
}
- public function getAdvertisedTokens() {
+ /**
+ * Get the tokens we expect to see advertised.
+ *
+ * @return string[]
+ */
+ public function getAdvertisedTokens(): array {
return [
'{contact.contact_type}' => 'Contact Type',
'{contact.do_not_email}' => 'Do Not Email',