Merge pull request #17641 from MegaphoneJon/core-1590
[civicrm-core.git] / ext / flexmailer / src / Listener / DefaultComposer.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11 namespace Civi\FlexMailer\Listener;
12
13 use Civi\FlexMailer\Event\ComposeBatchEvent;
14 use Civi\FlexMailer\Event\RunEvent;
15 use Civi\FlexMailer\FlexMailerTask;
16 use Civi\Token\TokenProcessor;
17 use Civi\Token\TokenRow;
18
19 /**
20 * Class DefaultComposer
21 * @package Civi\FlexMailer\Listener
22 *
23 * The DefaultComposer uses a TokenProcessor to generate all messages as
24 * a batch.
25 */
26 class DefaultComposer extends BaseListener {
27
28 public function onRun(RunEvent $e) {
29 // FIXME: This probably doesn't belong here...
30 if (defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY) {
31 \CRM_Core_Smarty::registerStringResource();
32 }
33 }
34
35 /**
36 * Determine whether this composer knows how to handle this mailing.
37 *
38 * @param \CRM_Mailing_DAO_Mailing $mailing
39 * @return bool
40 */
41 public function isSupported(\CRM_Mailing_DAO_Mailing $mailing) {
42 return TRUE;
43 }
44
45 /**
46 * Given a mailing and a batch of recipients, prepare
47 * the individual messages (headers and body) for each.
48 *
49 * @param \Civi\FlexMailer\Event\ComposeBatchEvent $e
50 */
51 public function onCompose(ComposeBatchEvent $e) {
52 if (!$this->isActive() || !$this->isSupported($e->getMailing())) {
53 return;
54 }
55
56 $tp = new TokenProcessor(\Civi::service('dispatcher'),
57 $this->createTokenProcessorContext($e));
58
59 $tpls = $this->createMessageTemplates($e);
60 $tp->addMessage('subject', $tpls['subject'], 'text/plain');
61 $tp->addMessage('body_text', isset($tpls['text']) ? $tpls['text'] : '',
62 'text/plain');
63 $tp->addMessage('body_html', isset($tpls['html']) ? $tpls['html'] : '',
64 'text/html');
65
66 $hasContent = FALSE;
67 foreach ($e->getTasks() as $key => $task) {
68 /** @var \Civi\FlexMailer\FlexMailerTask $task */
69 if (!$task->hasContent()) {
70 $tp->addRow()->context($this->createTokenRowContext($e, $task));
71 $hasContent = TRUE;
72 }
73 }
74
75 if (!$hasContent) {
76 return;
77 }
78
79 $tp->evaluate();
80
81 foreach ($tp->getRows() as $row) {
82 /** @var \Civi\Token\TokenRow $row */
83 /** @var \Civi\FlexMailer\FlexMailerTask $task */
84 $task = $row->context['flexMailerTask'];
85 $task->setMailParams(array_merge(
86 $this->createMailParams($e, $task, $row),
87 $task->getMailParams()
88 ));
89 }
90 }
91
92 /**
93 * Define the contextual parameters for the token-processor.
94 *
95 * @param \Civi\FlexMailer\Event\ComposeBatchEvent $e
96 * @return array
97 */
98 public function createTokenProcessorContext(ComposeBatchEvent $e) {
99 $context = array(
100 'controller' => get_class($this),
101 // FIXME: Use template_type, template_options
102 'smarty' => defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY ? TRUE : FALSE,
103 'mailing' => $e->getMailing(),
104 'mailingId' => $e->getMailing()->id,
105 );
106 return $context;
107 }
108
109 /**
110 * Create contextual data for a message recipient.
111 *
112 * @param \Civi\FlexMailer\Event\ComposeBatchEvent $e
113 * @param \Civi\FlexMailer\FlexMailerTask $task
114 * @return array
115 * Contextual data describing the recipient.
116 * Typical values are `contactId` or `mailingJobId`.
117 */
118 public function createTokenRowContext(
119 ComposeBatchEvent $e,
120 FlexMailerTask $task
121 ) {
122 return array(
123 'contactId' => $task->getContactId(),
124 'mailingJobId' => $e->getJob()->id,
125 'mailingActionTarget' => array(
126 'id' => $task->getEventQueueId(),
127 'hash' => $task->getHash(),
128 'email' => $task->getAddress(),
129 ),
130 'flexMailerTask' => $task,
131 );
132 }
133
134 /**
135 * For a given task, prepare the mailing.
136 *
137 * @param \Civi\FlexMailer\Event\ComposeBatchEvent $e
138 * @param \Civi\FlexMailer\FlexMailerTask $task
139 * @param \Civi\Token\TokenRow $row
140 * @return array
141 * A list of email parameters, such as "Subject", "text", and/or "html".
142 * @see \CRM_Utils_Hook::alterMailParams
143 */
144 public function createMailParams(
145 ComposeBatchEvent $e,
146 FlexMailerTask $task,
147 TokenRow $row
148 ) {
149 return array(
150 'Subject' => $row->render('subject'),
151 'text' => $row->render('body_text'),
152 'html' => $row->render('body_html'),
153 );
154 }
155
156 /**
157 * Generate the message templates for use with token-processor.
158 *
159 * @param \Civi\FlexMailer\Event\ComposeBatchEvent $e
160 * @return array
161 * A list of templates. Some combination of:
162 * - subject: string
163 * - html: string
164 * - text: string
165 */
166 public function createMessageTemplates(ComposeBatchEvent $e) {
167 $templates = $e->getMailing()->getTemplates();
168 if ($this->isClickTracking($e)) {
169 $templates = $this->applyClickTracking($e, $templates);
170 }
171 return $templates;
172 }
173
174 /**
175 * (Tentative) Alter hyperlinks to perform click-tracking.
176 *
177 * This functionality probably belongs somewhere else. The
178 * current placement feels quirky, and it's hard to inspect
179 * via `cv debug:event-dispatcher', but it produces the expected
180 * interactions among tokens and click-tracking.
181 *
182 * @param \Civi\FlexMailer\Event\ComposeBatchEvent $e
183 * @param array $templates
184 * @return array
185 * Updated templates.
186 */
187 protected function applyClickTracking(ComposeBatchEvent $e, $templates) {
188 $mailing = $e->getMailing();
189
190 if (!empty($templates['html'])) {
191 $templates['html'] = \Civi::service('civi_flexmailer_html_click_tracker')
192 ->filterContent($templates['html'], $mailing->id,
193 '{action.eventQueueId}');
194 }
195 if (!empty($templates['text'])) {
196 $templates['text'] = \Civi::service('civi_flexmailer_text_click_tracker')
197 ->filterContent($templates['text'], $mailing->id,
198 '{action.eventQueueId}');
199 }
200
201 return $templates;
202 }
203
204 /**
205 * Determine whether to enable click-tracking.
206 *
207 * @param \Civi\FlexMailer\Event\ComposeBatchEvent $e
208 * @return bool
209 */
210 public function isClickTracking(ComposeBatchEvent $e) {
211 // Don't track clicks on previews. Doing so would accumulate a lot
212 // of garbage data.
213 return $e->getMailing()->url_tracking && !$e->isPreview();
214 }
215
216 }