4 use Civi\Token\Event\TokenRenderEvent
;
5 use Civi\Token\Event\TokenValueEvent
;
6 use Symfony\Component\EventDispatcher\EventSubscriberInterface
;
9 * Class TokenCompatSubscriber
12 * This class provides a compatibility layer for using CRM_Utils_Token
13 * helpers within TokenProcessor.
15 * THIS IS NOT A GOOD EXAMPLE TO EMULATE. The class exists to two
16 * bridge two different designs. CRM_Utils_Token has some
17 * undesirable elements (like iterative token substitution).
18 * However, if you're refactor CRM_Utils_Token or improve the
19 * bridge, then it makes sense to update this class.
21 class TokenCompatSubscriber
implements EventSubscriberInterface
{
26 public static function getSubscribedEvents() {
28 Events
::TOKEN_EVALUATE
=> 'onEvaluate',
29 Events
::TOKEN_RENDER
=> 'onRender',
36 * @param TokenValueEvent $e
37 * @throws TokenException
39 public function onEvaluate(TokenValueEvent
$e) {
40 // For reasons unknown, replaceHookTokens requires a pre-computed list of
41 // hook *categories* (aka entities aka namespaces). We'll cache
42 // this in the TokenProcessor's context.
44 $hookTokens = array();
45 \CRM_Utils_Hook
::tokens($hookTokens);
46 $categories = array_keys($hookTokens);
47 $e->getTokenProcessor()->context
['hookTokenCategories'] = $categories;
49 $messageTokens = $e->getTokenProcessor()->getMessageTokens();
51 foreach ($e->getRows() as $row) {
52 /** @var int $contactId */
53 $contactId = $row->context
['contactId'];
54 if (empty($row->context
['contact'])) {
56 array('contact_id', '=', $contactId, 0, 0),
58 list($contact, $_) = \CRM_Contact_BAO_Query
::apiQuery($params);
59 $contact = reset($contact); //CRM-4524
60 if (!$contact ||
is_a($contact, 'CRM_Core_Error')) {
61 // FIXME: Need to differentiate errors which kill the batch vs the individual row.
62 throw new TokenException("Failed to generate token data. Invalid contact ID: " . $row->context
['contactId']);
65 //update value of custom field token
66 if (!empty($messageTokens['contact'])) {
67 foreach ($messageTokens['contact'] as $token) {
68 if (\CRM_Core_BAO_CustomField
::getKeyID($token)) {
69 $contact[$token] = civicrm_api3('Contact', 'getvalue', array(
78 $contact = $row->context
['contact'];
81 if (!empty($row->context
['tmpTokenParams'])) {
82 // merge activity tokens with contact array
83 // this is pretty weird.
84 $contact = array_merge($contact, $row->context
['tmpTokenParams']);
87 $contactArray = !is_array($contactId) ?
array($contactId => $contact) : $contact;
89 // Note: This is a small contract change from the past; data should be missing
91 \CRM_Utils_Hook
::tokenValues($contactArray,
93 empty($row->context
['mailingJob']) ?
NULL : $row->context
['mailingJob']->id
,
95 $row->context
['controller']
98 // merge the custom tokens in the $contact array
99 if (!empty($contactArray[$contactId])) {
100 $contact = array_merge($contact, $contactArray[$contactId]);
102 $row->context('contact', $contact);
107 * Apply the various CRM_Utils_Token helpers.
109 * @param TokenRenderEvent $e
111 public function onRender(TokenRenderEvent
$e) {
112 $isHtml = ($e->message
['format'] == 'text/html');
113 $useSmarty = !empty($e->context
['smarty']);
115 $domain = \CRM_Core_BAO_Domain
::getDomain();
116 $e->string = \CRM_Utils_Token
::replaceDomainTokens($e->string, $domain, $isHtml, $e->message
['tokens'], $useSmarty);
118 if (!empty($e->context
['contact'])) {
119 $e->string = \CRM_Utils_Token
::replaceContactTokens($e->string, $e->context
['contact'], $isHtml, $e->message
['tokens'], TRUE, $useSmarty);
121 // FIXME: This may depend on $contact being merged with hook values.
122 $e->string = \CRM_Utils_Token
::replaceHookTokens($e->string, $e->context
['contact'], $e->context
['hookTokenCategories'], $isHtml, $useSmarty);
124 \CRM_Utils_Token
::replaceGreetingTokens($e->string, $e->context
['contact'], $e->context
['contact']['contact_id'], NULL, $useSmarty);
128 $smarty = \CRM_Core_Smarty
::singleton();
129 $e->string = $smarty->fetch("string:" . $e->string);