Merge pull request #14811 from eileenmcnaughton/ex1
[civicrm-core.git] / Civi / Token / TokenCompatSubscriber.php
CommitLineData
43ceab3f
TO
1<?php
2namespace Civi\Token;
3
4use Civi\Token\Event\TokenRenderEvent;
5use Civi\Token\Event\TokenValueEvent;
6use Symfony\Component\EventDispatcher\EventSubscriberInterface;
7
8/**
9 * Class TokenCompatSubscriber
10 * @package Civi\Token
11 *
12 * This class provides a compatibility layer for using CRM_Utils_Token
13 * helpers within TokenProcessor.
14 *
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.
20 */
21class TokenCompatSubscriber implements EventSubscriberInterface {
22
23 /**
24 * @inheritDoc
25 */
26 public static function getSubscribedEvents() {
c64f69d9 27 return [
43ceab3f
TO
28 Events::TOKEN_EVALUATE => 'onEvaluate',
29 Events::TOKEN_RENDER => 'onRender',
c64f69d9 30 ];
43ceab3f
TO
31 }
32
33 /**
34 * Load token data.
35 *
34f3bbd9 36 * @param \Civi\Token\Event\TokenValueEvent $e
43ceab3f
TO
37 * @throws TokenException
38 */
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.
43
c64f69d9 44 $hookTokens = [];
43ceab3f
TO
45 \CRM_Utils_Hook::tokens($hookTokens);
46 $categories = array_keys($hookTokens);
47 $e->getTokenProcessor()->context['hookTokenCategories'] = $categories;
48
49 $messageTokens = $e->getTokenProcessor()->getMessageTokens();
50
51 foreach ($e->getRows() as $row) {
d4afa032
AS
52 if (empty($row->context['contactId'])) {
53 continue;
54 }
ee299f14 55 /** @var int $contactId */
7558391f 56 $contactId = $row->context['contactId'];
43ceab3f 57 if (empty($row->context['contact'])) {
c64f69d9
CW
58 $params = [
59 ['contact_id', '=', $contactId, 0, 0],
60 ];
43ceab3f 61 list($contact, $_) = \CRM_Contact_BAO_Query::apiQuery($params);
34f3bbd9
SL
62 //CRM-4524
63 $contact = reset($contact);
43ceab3f
TO
64 if (!$contact || is_a($contact, 'CRM_Core_Error')) {
65 // FIXME: Need to differentiate errors which kill the batch vs the individual row.
66 throw new TokenException("Failed to generate token data. Invalid contact ID: " . $row->context['contactId']);
67 }
a0fcf992 68
4e9b6a62 69 //update value of custom field token
70 if (!empty($messageTokens['contact'])) {
71 foreach ($messageTokens['contact'] as $token) {
72 if (\CRM_Core_BAO_CustomField::getKeyID($token)) {
c64f69d9 73 $contact[$token] = civicrm_api3('Contact', 'getvalue', [
8640061b 74 'return' => $token,
75 'id' => $contactId,
c64f69d9 76 ]);
4e9b6a62 77 }
1ae59975 78 }
a0fcf992 79 }
43ceab3f
TO
80 }
81 else {
82 $contact = $row->context['contact'];
83 }
84
85 if (!empty($row->context['tmpTokenParams'])) {
86 // merge activity tokens with contact array
87 // this is pretty weird.
88 $contact = array_merge($contact, $row->context['tmpTokenParams']);
89 }
90
c64f69d9 91 $contactArray = !is_array($contactId) ? [$contactId => $contact] : $contact;
7558391f 92
43ceab3f
TO
93 // Note: This is a small contract change from the past; data should be missing
94 // less randomly.
7558391f 95 \CRM_Utils_Hook::tokenValues($contactArray,
96 (array) $contactId,
1b03e966 97 empty($row->context['mailingJobId']) ? NULL : $row->context['mailingJobId'],
43ceab3f
TO
98 $messageTokens,
99 $row->context['controller']
100 );
101
051938c6 102 // merge the custom tokens in the $contact array
103 if (!empty($contactArray[$contactId])) {
104 $contact = array_merge($contact, $contactArray[$contactId]);
105 }
43ceab3f
TO
106 $row->context('contact', $contact);
107 }
108 }
109
110 /**
111 * Apply the various CRM_Utils_Token helpers.
112 *
34f3bbd9 113 * @param \Civi\Token\Event\TokenRenderEvent $e
43ceab3f
TO
114 */
115 public function onRender(TokenRenderEvent $e) {
116 $isHtml = ($e->message['format'] == 'text/html');
117 $useSmarty = !empty($e->context['smarty']);
118
f2d12098
TO
119 $domain = \CRM_Core_BAO_Domain::getDomain();
120 $e->string = \CRM_Utils_Token::replaceDomainTokens($e->string, $domain, $isHtml, $e->message['tokens'], $useSmarty);
43ceab3f
TO
121
122 if (!empty($e->context['contact'])) {
8640061b 123 $e->string = \CRM_Utils_Token::replaceContactTokens($e->string, $e->context['contact'], $isHtml, $e->message['tokens'], TRUE, $useSmarty);
43ceab3f
TO
124
125 // FIXME: This may depend on $contact being merged with hook values.
126 $e->string = \CRM_Utils_Token::replaceHookTokens($e->string, $e->context['contact'], $e->context['hookTokenCategories'], $isHtml, $useSmarty);
8640061b 127
128 \CRM_Utils_Token::replaceGreetingTokens($e->string, $e->context['contact'], $e->context['contact']['contact_id'], NULL, $useSmarty);
43ceab3f
TO
129 }
130
131 if ($useSmarty) {
132 $smarty = \CRM_Core_Smarty::singleton();
133 $e->string = $smarty->fetch("string:" . $e->string);
134 }
135 }
136
137}