Merge pull request #20479 from demeritcowboy/userload
[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 [
4c367668
TO
28 'civi.token.eval' => 'onEvaluate',
29 'civi.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) {
12d88807 40 // For reasons unknown, replaceHookTokens used to require a pre-computed list of
41 // hook *categories* (aka entities aka namespaces). We cache
42 // this in the TokenProcessor's context but can likely remove it now.
43ceab3f 43
12d88807 44 $e->getTokenProcessor()->context['hookTokenCategories'] = \CRM_Utils_Token::getTokenCategories();
43ceab3f
TO
45
46 $messageTokens = $e->getTokenProcessor()->getMessageTokens();
5425ccb5 47 $returnProperties = array_fill_keys($messageTokens['contact'] ?? [], 1);
48 $returnProperties = array_merge(\CRM_Contact_BAO_Query::defaultReturnProperties(), $returnProperties);
43ceab3f
TO
49
50 foreach ($e->getRows() as $row) {
d4afa032
AS
51 if (empty($row->context['contactId'])) {
52 continue;
53 }
ee299f14 54 /** @var int $contactId */
7558391f 55 $contactId = $row->context['contactId'];
43ceab3f 56 if (empty($row->context['contact'])) {
c64f69d9
CW
57 $params = [
58 ['contact_id', '=', $contactId, 0, 0],
59 ];
5425ccb5 60 [$contact] = \CRM_Contact_BAO_Query::apiQuery($params, $returnProperties ?? NULL);
34f3bbd9
SL
61 //CRM-4524
62 $contact = reset($contact);
5425ccb5 63 // Test cover for greeting in CRM_Core_BAO_ActionScheduleTest::testMailer
64 $contact['email_greeting'] = $contact['email_greeting_display'] ?? '';
65 $contact['postal_greeting'] = $contact['postal_greeting_display'] ?? '';
66 $contact['addressee'] = $contact['address_display'] ?? '';
43ceab3f
TO
67 if (!$contact || is_a($contact, 'CRM_Core_Error')) {
68 // FIXME: Need to differentiate errors which kill the batch vs the individual row.
5425ccb5 69 \Civi::log()->debug('Failed to generate token data. Invalid contact ID: ' . $row->context['contactId']);
7f985f8c 70 continue;
43ceab3f 71 }
a0fcf992 72
4e9b6a62 73 //update value of custom field token
74 if (!empty($messageTokens['contact'])) {
75 foreach ($messageTokens['contact'] as $token) {
76 if (\CRM_Core_BAO_CustomField::getKeyID($token)) {
5425ccb5 77 $contact[$token] = \CRM_Core_BAO_CustomField::displayValue($contact[$token], \CRM_Core_BAO_CustomField::getKeyID($token));
4e9b6a62 78 }
1ae59975 79 }
a0fcf992 80 }
43ceab3f
TO
81 }
82 else {
83 $contact = $row->context['contact'];
84 }
85
86 if (!empty($row->context['tmpTokenParams'])) {
87 // merge activity tokens with contact array
88 // this is pretty weird.
89 $contact = array_merge($contact, $row->context['tmpTokenParams']);
90 }
91
590111ef 92 $contactArray = [$contactId => $contact];
7558391f 93 \CRM_Utils_Hook::tokenValues($contactArray,
590111ef 94 [$contactId],
1b03e966 95 empty($row->context['mailingJobId']) ? NULL : $row->context['mailingJobId'],
43ceab3f
TO
96 $messageTokens,
97 $row->context['controller']
98 );
99
051938c6 100 // merge the custom tokens in the $contact array
101 if (!empty($contactArray[$contactId])) {
102 $contact = array_merge($contact, $contactArray[$contactId]);
103 }
43ceab3f
TO
104 $row->context('contact', $contact);
105 }
106 }
107
108 /**
109 * Apply the various CRM_Utils_Token helpers.
110 *
34f3bbd9 111 * @param \Civi\Token\Event\TokenRenderEvent $e
43ceab3f
TO
112 */
113 public function onRender(TokenRenderEvent $e) {
114 $isHtml = ($e->message['format'] == 'text/html');
115 $useSmarty = !empty($e->context['smarty']);
116
f2d12098
TO
117 $domain = \CRM_Core_BAO_Domain::getDomain();
118 $e->string = \CRM_Utils_Token::replaceDomainTokens($e->string, $domain, $isHtml, $e->message['tokens'], $useSmarty);
43ceab3f
TO
119
120 if (!empty($e->context['contact'])) {
3645517f 121 \CRM_Utils_Token::replaceGreetingTokens($e->string, $e->context['contact'], $e->context['contact']['contact_id'], NULL, $useSmarty);
8640061b 122 $e->string = \CRM_Utils_Token::replaceContactTokens($e->string, $e->context['contact'], $isHtml, $e->message['tokens'], TRUE, $useSmarty);
43ceab3f
TO
123
124 // FIXME: This may depend on $contact being merged with hook values.
125 $e->string = \CRM_Utils_Token::replaceHookTokens($e->string, $e->context['contact'], $e->context['hookTokenCategories'], $isHtml, $useSmarty);
126 }
127
128 if ($useSmarty) {
129 $smarty = \CRM_Core_Smarty::singleton();
130 $e->string = $smarty->fetch("string:" . $e->string);
131 }
132 }
133
134}