Merge pull request #4882 from colemanw/CRM-15789
[civicrm-core.git] / CRM / Core / BAO / MessageTemplate.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
39de6fd5 4 | CiviCRM version 4.6 |
6a488035 5 +--------------------------------------------------------------------+
06b69b18 6 | Copyright CiviCRM LLC (c) 2004-2014 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26*/
27
28/**
29 *
30 * @package CRM
06b69b18 31 * @copyright CiviCRM LLC (c) 2004-2014
6a488035
TO
32 * $Id$
33 *
34 */
35
36require_once 'Mail/mime.php';
b5c2afd0
EM
37
38/**
39 * Class CRM_Core_BAO_MessageTemplate
40 */
c6327d7d 41class CRM_Core_BAO_MessageTemplate extends CRM_Core_DAO_MessageTemplate {
6a488035
TO
42
43 /**
c490a46a 44 * Fetch object based on array of properties
6a488035 45 *
6a0b768e
TO
46 * @param array $params
47 * (reference ) an assoc array of name/value pairs.
48 * @param array $defaults
49 * (reference ) an assoc array to hold the flattened values.
6a488035 50 *
c490a46a 51 * @return CRM_Core_BAO_MessageTemplate object
6a488035
TO
52 * @static
53 */
00be9182 54 public static function retrieve(&$params, &$defaults) {
c6327d7d 55 $messageTemplates = new CRM_Core_DAO_MessageTemplate();
6a488035
TO
56 $messageTemplates->copyValues($params);
57 if ($messageTemplates->find(TRUE)) {
58 CRM_Core_DAO::storeValues($messageTemplates, $defaults);
59 return $messageTemplates;
60 }
61 return NULL;
62 }
63
64 /**
100fef9d 65 * Update the is_active flag in the db
6a488035 66 *
6a0b768e
TO
67 * @param int $id
68 * Id of the database record.
69 * @param bool $is_active
70 * Value we want to set the is_active field.
6a488035 71 *
e60f24eb 72 * @return Object DAO object on sucess, NULL otherwise
6a488035
TO
73 * @static
74 */
00be9182 75 public static function setIsActive($id, $is_active) {
c6327d7d 76 return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_MessageTemplate', $id, 'is_active', $is_active);
6a488035
TO
77 }
78
79 /**
100fef9d 80 * Add the Message Templates
6a488035 81 *
6a0b768e
TO
82 * @param array $params
83 * Reference array contains the values submitted by the form.
6a488035 84 *
6a488035
TO
85 * @static
86 *
87 * @return object
88 */
00be9182 89 public static function add(&$params) {
3c8059c8
KM
90 $hook = empty($params['id']) ? 'create' : 'edit';
91 CRM_Utils_Hook::pre($hook, 'MessageTemplate', CRM_Utils_Array::value('id', $params), $params);
c39c0aa1 92
c6327d7d 93 $messageTemplates = new CRM_Core_DAO_MessageTemplate();
6a488035 94 $messageTemplates->copyValues($params);
6a488035 95 $messageTemplates->save();
c39c0aa1 96
c9606a53 97 CRM_Utils_Hook::post($hook, 'MessageTemplate', $messageTemplates->id, $messageTemplates);
6a488035
TO
98 return $messageTemplates;
99 }
100
101 /**
100fef9d 102 * Delete the Message Templates
6a488035 103 *
6a488035
TO
104 * @static
105 *
100fef9d 106 * @param int $messageTemplatesID
77b97be7 107 *
6a488035
TO
108 * @return object
109 */
00be9182 110 public static function del($messageTemplatesID) {
6a488035
TO
111 // make sure messageTemplatesID is an integer
112 if (!CRM_Utils_Rule::positiveInteger($messageTemplatesID)) {
113 CRM_Core_Error::fatal(ts('Invalid Message template'));
114 }
115
116 // Set mailing msg template col to NULL
117 $query = "UPDATE civicrm_mailing
118 SET msg_template_id = NULL
119 WHERE msg_template_id = %1";
5f351616 120
121 $params = array(1 => array($messageTemplatesID, 'Integer'));
6a488035
TO
122 CRM_Core_DAO::executeQuery($query, $params);
123
c6327d7d 124 $messageTemplates = new CRM_Core_DAO_MessageTemplate();
6a488035
TO
125 $messageTemplates->id = $messageTemplatesID;
126 $messageTemplates->delete();
127 CRM_Core_Session::setStatus(ts('Selected message template has been deleted.'), ts('Deleted'), 'success');
128 }
129
130 /**
100fef9d 131 * Get the Message Templates
6a488035 132 *
6a488035
TO
133 * @static
134 *
dd244018
EM
135 * @param bool $all
136 *
6a488035
TO
137 * @return object
138 */
00be9182 139 public static function getMessageTemplates($all = TRUE, $isSMS = FALSE) {
6a488035
TO
140 $msgTpls = array();
141
c6327d7d 142 $messageTemplates = new CRM_Core_DAO_MessageTemplate();
6a488035 143 $messageTemplates->is_active = 1;
1e035d58 144 $messageTemplates->is_sms = $isSMS;
6a488035
TO
145
146 if (!$all) {
147 $messageTemplates->workflow_id = 'NULL';
148 }
149 $messageTemplates->find();
150 while ($messageTemplates->fetch()) {
151 $msgTpls[$messageTemplates->id] = $messageTemplates->msg_title;
152 }
153 asort($msgTpls);
154 return $msgTpls;
155 }
156
b5c2afd0 157 /**
100fef9d 158 * @param int $contactId
b5c2afd0 159 * @param $email
100fef9d 160 * @param int $messageTemplateID
b5c2afd0
EM
161 * @param $from
162 *
e60f24eb 163 * @return bool|NULL
b5c2afd0 164 */
00be9182 165 public static function sendReminder($contactId, $email, $messageTemplateID, $from) {
6a488035 166
c6327d7d 167 $messageTemplates = new CRM_Core_DAO_MessageTemplate();
6a488035
TO
168 $messageTemplates->id = $messageTemplateID;
169
170 $domain = CRM_Core_BAO_Domain::getDomain();
171 $result = NULL;
172 $hookTokens = array();
173
174 if ($messageTemplates->find(TRUE)) {
175 $body_text = $messageTemplates->msg_text;
176 $body_html = $messageTemplates->msg_html;
177 $body_subject = $messageTemplates->msg_subject;
178 if (!$body_text) {
179 $body_text = CRM_Utils_String::htmlToText($body_html);
180 }
181
182 $params = array(array('contact_id', '=', $contactId, 0, 0));
183 list($contact, $_) = CRM_Contact_BAO_Query::apiQuery($params);
184
185 //CRM-4524
186 $contact = reset($contact);
187
188 if (!$contact || is_a($contact, 'CRM_Core_Error')) {
189 return NULL;
190 }
191
192 //CRM-5734
193
194 // get tokens to be replaced
195 $tokens = array_merge(CRM_Utils_Token::getTokens($body_text),
196 CRM_Utils_Token::getTokens($body_html),
197 CRM_Utils_Token::getTokens($body_subject));
198
199 // get replacement text for these tokens
200 $returnProperties = array("preferred_mail_format" => 1);
c39c0aa1 201 if (isset($tokens['contact'])) {
6a488035 202 foreach ($tokens['contact'] as $key => $value) {
c39c0aa1 203 $returnProperties[$value] = 1;
6a488035
TO
204 }
205 }
206 list($details) = CRM_Utils_Token::getTokenDetails(array($contactId),
207 $returnProperties,
ab8a593e 208 NULL, NULL, FALSE,
6a488035 209 $tokens,
c6327d7d 210 'CRM_Core_BAO_MessageTemplate');
481a74f4 211 $contact = reset($details);
6a488035
TO
212
213 // call token hook
c39c0aa1 214 $hookTokens = array();
6a488035
TO
215 CRM_Utils_Hook::tokens($hookTokens);
216 $categories = array_keys($hookTokens);
217
c39c0aa1 218 // do replacements in text and html body
6a488035
TO
219 $type = array('html', 'text');
220 foreach ($type as $key => $value) {
221 $bodyType = "body_{$value}";
222 if ($$bodyType) {
223 CRM_Utils_Token::replaceGreetingTokens($$bodyType, NULL, $contact['contact_id']);
4eeb9a5b 224 $$bodyType = CRM_Utils_Token::replaceDomainTokens($$bodyType, $domain, TRUE, $tokens, TRUE);
ab8a593e 225 $$bodyType = CRM_Utils_Token::replaceContactTokens($$bodyType, $contact, FALSE, $tokens, FALSE, TRUE);
4eeb9a5b 226 $$bodyType = CRM_Utils_Token::replaceComponentTokens($$bodyType, $contact, $tokens, TRUE);
d3e86119 227 $$bodyType = CRM_Utils_Token::replaceHookTokens($$bodyType, $contact, $categories, TRUE);
6a488035
TO
228 }
229 }
230 $html = $body_html;
231 $text = $body_text;
232
4ee279f4 233 $smarty = CRM_Core_Smarty::singleton();
234 foreach (array(
235 'text', 'html') as $elem) {
236 $$elem = $smarty->fetch("string:{$$elem}");
237 }
238
6a488035 239 // do replacements in message subject
ab8a593e 240 $messageSubject = CRM_Utils_Token::replaceContactTokens($body_subject, $contact, FALSE, $tokens);
4eeb9a5b
TO
241 $messageSubject = CRM_Utils_Token::replaceDomainTokens($messageSubject, $domain, TRUE, $tokens);
242 $messageSubject = CRM_Utils_Token::replaceComponentTokens($messageSubject, $contact, $tokens, TRUE);
243 $messageSubject = CRM_Utils_Token::replaceHookTokens($messageSubject, $contact, $categories, TRUE);
6a488035 244
4ee279f4 245 $messageSubject = $smarty->fetch("string:{$messageSubject}");
246
6a488035
TO
247 // set up the parameters for CRM_Utils_Mail::send
248 $mailParams = array(
249 'groupName' => 'Scheduled Reminder Sender',
250 'from' => $from,
251 'toName' => $contact['display_name'],
252 'toEmail' => $email,
253 'subject' => $messageSubject,
254 );
255 if (!$html || $contact['preferred_mail_format'] == 'Text' ||
256 $contact['preferred_mail_format'] == 'Both'
257 ) {
258 // render the &amp; entities in text mode, so that the links work
259 $mailParams['text'] = str_replace('&amp;', '&', $text);
260 }
261 if ($html && ($contact['preferred_mail_format'] == 'HTML' ||
262 $contact['preferred_mail_format'] == 'Both'
263 )) {
264 $mailParams['html'] = $html;
265 }
266
267 $result = CRM_Utils_Mail::send($mailParams);
268 }
269
270 $messageTemplates->free();
271
272 return $result;
273 }
274
275 /**
276 * Revert a message template to its default subject+text+HTML state
277 *
6a0b768e 278 * @param int id id of the template
6a488035
TO
279 *
280 * @return void
281 */
00be9182 282 public static function revert($id) {
6a488035
TO
283 $diverted = new self;
284 $diverted->id = (int) $id;
285 $diverted->find(1);
286
287 if ($diverted->N != 1) {
288 CRM_Core_Error::fatal(ts('Did not find a message template with id of %1.', array(1 => $id)));
289 }
290
291 $orig = new self;
292 $orig->workflow_id = $diverted->workflow_id;
293 $orig->is_reserved = 1;
294 $orig->find(1);
295
296 if ($orig->N != 1) {
297 CRM_Core_Error::fatal(ts('Message template with id of %1 does not have a default to revert to.', array(1 => $id)));
298 }
299
300 $diverted->msg_subject = $orig->msg_subject;
301 $diverted->msg_text = $orig->msg_text;
302 $diverted->msg_html = $orig->msg_html;
303 $diverted->pdf_format_id = is_null($orig->pdf_format_id) ? 'null' : $orig->pdf_format_id;
304 $diverted->save();
305 }
306
307 /**
308 * Send an email from the specified template based on an array of params
309 *
6a0b768e
TO
310 * @param array $params
311 * A string-keyed array of function params, see function body for details.
6a488035
TO
312 *
313 * @return array of four parameters: a boolean whether the email was sent, and the subject, text and HTML templates
314 */
00be9182 315 public static function sendTemplate($params) {
6a488035
TO
316 $defaults = array(
317 // option group name of the template
318 'groupName' => NULL,
319 // option value name of the template
320 'valueName' => NULL,
321 // ID of the template
322 'messageTemplateID' => NULL,
323 // contact id if contact tokens are to be replaced
324 'contactId' => NULL,
325 // additional template params (other than the ones already set in the template singleton)
326 'tplParams' => array(),
327 // the From: header
328 'from' => NULL,
329 // the recipient’s name
330 'toName' => NULL,
331 // the recipient’s email - mail is sent only if set
332 'toEmail' => NULL,
333 // the Cc: header
334 'cc' => NULL,
335 // the Bcc: header
336 'bcc' => NULL,
337 // the Reply-To: header
338 'replyTo' => NULL,
339 // email attachments
340 'attachments' => NULL,
341 // whether this is a test email (and hence should include the test banner)
342 'isTest' => FALSE,
343 // filename of optional PDF version to add as attachment (do not include path)
344 'PDFFilename' => NULL,
345 );
346 $params = array_merge($defaults, $params);
347
348 if ((!$params['groupName'] ||
349 !$params['valueName']
350 ) &&
351 !$params['messageTemplateID']
352 ) {
353 CRM_Core_Error::fatal(ts("Message template's option group and/or option value or ID missing."));
354 }
355
356 if ($params['messageTemplateID']) {
357 // fetch the three elements from the db based on id
358 $query = 'SELECT msg_subject subject, msg_text text, msg_html html, pdf_format_id format
359 FROM civicrm_msg_template mt
360 WHERE mt.id = %1 AND mt.is_default = 1';
361 $sqlParams = array(1 => array($params['messageTemplateID'], 'String'));
362 }
363 else {
364 // fetch the three elements from the db based on option_group and option_value names
365 $query = 'SELECT msg_subject subject, msg_text text, msg_html html, pdf_format_id format
366 FROM civicrm_msg_template mt
367 JOIN civicrm_option_value ov ON workflow_id = ov.id
368 JOIN civicrm_option_group og ON ov.option_group_id = og.id
369 WHERE og.name = %1 AND ov.name = %2 AND mt.is_default = 1';
370 $sqlParams = array(1 => array($params['groupName'], 'String'), 2 => array($params['valueName'], 'String'));
371 }
372 $dao = CRM_Core_DAO::executeQuery($query, $sqlParams);
373 $dao->fetch();
374
375 if (!$dao->N) {
376 if ($params['messageTemplateID']) {
377 CRM_Core_Error::fatal(ts('No such message template: id=%1.', array(1 => $params['messageTemplateID'])));
378 }
379 else {
380 CRM_Core_Error::fatal(ts('No such message template: option group %1, option value %2.', array(1 => $params['groupName'], 2 => $params['valueName'])));
381 }
382 }
383
384 $subject = $dao->subject;
385 $text = $dao->text;
386 $html = $dao->html;
387 $format = $dao->format;
388 $dao->free();
389
390 // add the test banner (if requested)
391 if ($params['isTest']) {
392 $query = "SELECT msg_subject subject, msg_text text, msg_html html
393 FROM civicrm_msg_template mt
394 JOIN civicrm_option_value ov ON workflow_id = ov.id
395 JOIN civicrm_option_group og ON ov.option_group_id = og.id
396 WHERE og.name = 'msg_tpl_workflow_meta' AND ov.name = 'test_preview' AND mt.is_default = 1";
397 $testDao = CRM_Core_DAO::executeQuery($query);
398 $testDao->fetch();
399
400 $subject = $testDao->subject . $subject;
401 $text = $testDao->text . $text;
402 $html = preg_replace('/<body(.*)$/im', "<body\\1\n{$testDao->html}", $html);
403 $testDao->free();
404 }
405
406 // replace tokens in the three elements (in subject as if it was the text body)
407 $domain = CRM_Core_BAO_Domain::getDomain();
408 $hookTokens = array();
409 $mailing = new CRM_Mailing_BAO_Mailing;
410 $mailing->body_text = $text;
411 $mailing->body_html = $html;
412 $tokens = $mailing->getTokens();
413 CRM_Utils_Hook::tokens($hookTokens);
414 $categories = array_keys($hookTokens);
415
416 $contactID = CRM_Utils_Array::value('contactId', $params);
417
418 if ($contactID) {
419 $contactParams = array('contact_id' => $contactID);
420 $returnProperties = array();
421
422 if (isset($tokens['text']['contact'])) {
423 foreach ($tokens['text']['contact'] as $name) {
424 $returnProperties[$name] = 1;
425 }
426 }
427
428 if (isset($tokens['html']['contact'])) {
429 foreach ($tokens['html']['contact'] as $name) {
430 $returnProperties[$name] = 1;
431 }
432 }
433 list($contact) = CRM_Utils_Token::getTokenDetails($contactParams,
434 $returnProperties,
435 FALSE, FALSE, NULL,
436 CRM_Utils_Token::flattenTokens($tokens),
437 // we should consider adding groupName and valueName here
438 'CRM_Core_BAO_MessageTemplate'
439 );
440 $contact = $contact[$contactID];
441 }
442
d8ea987e
SG
443 $subject = CRM_Utils_Token::replaceDomainTokens($subject, $domain, FALSE, $tokens['text'], TRUE);
444 $text = CRM_Utils_Token::replaceDomainTokens($text, $domain, FALSE, $tokens['text'], TRUE);
6a488035
TO
445 $html = CRM_Utils_Token::replaceDomainTokens($html, $domain, TRUE, $tokens['html'], TRUE);
446
447 if ($contactID) {
448 $subject = CRM_Utils_Token::replaceContactTokens($subject, $contact, FALSE, $tokens['text'], FALSE, TRUE);
449 $text = CRM_Utils_Token::replaceContactTokens($text, $contact, FALSE, $tokens['text'], FALSE, TRUE);
450 $html = CRM_Utils_Token::replaceContactTokens($html, $contact, FALSE, $tokens['html'], FALSE, TRUE);
451
452
453 $contactArray = array($contactID => $contact);
454 CRM_Utils_Hook::tokenValues($contactArray,
455 array($contactID),
456 NULL,
457 CRM_Utils_Token::flattenTokens($tokens),
458 // we should consider adding groupName and valueName here
459 'CRM_Core_BAO_MessageTemplate'
460 );
461 $contact = $contactArray[$contactID];
462
463 $subject = CRM_Utils_Token::replaceHookTokens($subject, $contact, $categories, TRUE);
464 $text = CRM_Utils_Token::replaceHookTokens($text, $contact, $categories, TRUE);
465 $html = CRM_Utils_Token::replaceHookTokens($html, $contact, $categories, TRUE);
466 }
467
4ee279f4 468 // strip whitespace from ends and turn into a single line
469 $subject = "{strip}$subject{/strip}";
470
471 // parse the three elements with Smarty
472
473
474 $smarty = CRM_Core_Smarty::singleton();
475 foreach ($params['tplParams'] as $name => $value) {
476 $smarty->assign($name, $value);
477 }
478 foreach (array(
479 'subject', 'text', 'html') as $elem) {
480 $$elem = $smarty->fetch("string:{$$elem}");
481 }
482
6a488035
TO
483 // send the template, honouring the target user’s preferences (if any)
484 $sent = FALSE;
485
486 // create the params array
487 $params['subject'] = $subject;
488 $params['text'] = $text;
489 $params['html'] = $html;
490
491 if ($params['toEmail']) {
492 $contactParams = array(array('email', 'LIKE', $params['toEmail'], 0, 1));
493 list($contact, $_) = CRM_Contact_BAO_Query::apiQuery($contactParams);
494
495 $prefs = array_pop($contact);
496
497 if (isset($prefs['preferred_mail_format']) and $prefs['preferred_mail_format'] == 'HTML') {
498 $params['text'] = NULL;
499 }
500
501 if (isset($prefs['preferred_mail_format']) and $prefs['preferred_mail_format'] == 'Text') {
502 $params['html'] = NULL;
503 }
504
505 $config = CRM_Core_Config::singleton();
9161952c 506 if (isset($params['isEmailPdf']) && $params['isEmailPdf'] == 1) {
d141946b 507 $pdfHtml = CRM_Contribute_BAO_ContributionPage::addInvoicePdfToEmail($params['contributionId'], $params['contactId']);
9161952c
PD
508 if (empty($params['attachments'])) {
509 $params['attachments'] = array();
510 }
33421d01 511 $params['attachments'][] = CRM_Utils_Mail::appendPDF('Invoice.pdf', $pdfHtml, $format);
9161952c 512 }
6a488035
TO
513 $pdf_filename = '';
514 if ($config->doNotAttachPDFReceipt &&
515 $params['PDFFilename'] &&
516 $params['html']
517 ) {
6a488035
TO
518 if (empty($params['attachments'])) {
519 $params['attachments'] = array();
520 }
383c047b 521 $params['attachments'][] = CRM_Utils_Mail::appendPDF($params['PDFFilename'], $params['html'], $format);
9849720e
RK
522 if (isset($params['tplParams']['email_comment'])) {
523 $params['html'] = $params['tplParams']['email_comment'];
d9e4ebe7 524 $params['text'] = strip_tags($params['tplParams']['email_comment']);
9849720e 525 }
6a488035
TO
526 }
527
528 $sent = CRM_Utils_Mail::send($params);
529
530 if ($pdf_filename) {
531 unlink($pdf_filename);
532 }
533 }
534
535 return array($sent, $subject, $text, $html);
536 }
537}