Merge pull request #9657 from totten/master-docblocks
[civicrm-core.git] / Civi / Token / TokenCompatSubscriber.php
1 <?php
2 namespace Civi\Token;
3
4 use Civi\Token\Event\TokenRenderEvent;
5 use Civi\Token\Event\TokenValueEvent;
6 use 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 */
21 class TokenCompatSubscriber implements EventSubscriberInterface {
22
23 /**
24 * @inheritDoc
25 */
26 public static function getSubscribedEvents() {
27 return array(
28 Events::TOKEN_EVALUATE => 'onEvaluate',
29 Events::TOKEN_RENDER => 'onRender',
30 );
31 }
32
33 /**
34 * Load token data.
35 *
36 * @param TokenValueEvent $e
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
44 $hookTokens = array();
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) {
52 /** @var int $contactId */
53 $contactId = $row->context['contactId'];
54 if (empty($row->context['contact'])) {
55 $params = array(
56 array('contact_id', '=', $contactId, 0, 0),
57 );
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']);
63 }
64 }
65 else {
66 $contact = $row->context['contact'];
67 }
68
69 if (!empty($row->context['tmpTokenParams'])) {
70 // merge activity tokens with contact array
71 // this is pretty weird.
72 $contact = array_merge($contact, $row->context['tmpTokenParams']);
73 }
74
75 $contactArray = !is_array($contactId) ? array($contactId => $contact) : $contact;
76
77 // Note: This is a small contract change from the past; data should be missing
78 // less randomly.
79 //\CRM_Utils_Hook::tokenValues($contact, $row->context['contactId']);
80 \CRM_Utils_Hook::tokenValues($contactArray,
81 (array) $contactId,
82 empty($row->context['mailingJob']) ? NULL : $row->context['mailingJob']->id,
83 $messageTokens,
84 $row->context['controller']
85 );
86
87 // merge the custom tokens in the $contact array
88 if (!empty($contactArray[$contactId])) {
89 $contact = array_merge($contact, $contactArray[$contactId]);
90 }
91 $row->context('contact', $contact);
92 }
93 }
94
95 /**
96 * Apply the various CRM_Utils_Token helpers.
97 *
98 * @param TokenRenderEvent $e
99 */
100 public function onRender(TokenRenderEvent $e) {
101 $isHtml = ($e->message['format'] == 'text/html');
102 $useSmarty = !empty($e->context['smarty']);
103
104 $e->string = \CRM_Utils_Token::replaceDomainTokens($e->string, \CRM_Core_BAO_Domain::getDomain(), $isHtml, $e->message['tokens'], $useSmarty);
105
106 if (!empty($e->context['contact'])) {
107 $e->string = \CRM_Utils_Token::replaceContactTokens($e->string, $e->context['contact'], $isHtml, $e->message['tokens'], FALSE, $useSmarty);
108
109 // FIXME: This may depend on $contact being merged with hook values.
110 $e->string = \CRM_Utils_Token::replaceHookTokens($e->string, $e->context['contact'], $e->context['hookTokenCategories'], $isHtml, $useSmarty);
111
112 \CRM_Utils_Token::replaceGreetingTokens($e->string, NULL, $e->context['contact']['contact_id'], NULL, $useSmarty);
113 }
114
115 if ($useSmarty) {
116 $smarty = \CRM_Core_Smarty::singleton();
117 $e->string = $smarty->fetch("string:" . $e->string);
118 }
119 }
120
121 }