<?php
/**
* @file classes/mail/MailTemplate.inc.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class MailTemplate
* @ingroup mail
*
* @brief Subclass of Mail for mailing a template email.
*/
import('lib.pkp.classes.mail.Mail');
define('MAIL_ERROR_INVALID_EMAIL', 0x000001);
class MailTemplate extends Mail {
/** @var object The context this message relates to */
var $context;
/** @var boolean whether to include the context's signature */
var $includeSignature;
/** @var string Key of the email template we are using */
var $emailKey;
/** @var string locale of this template */
var $locale;
/** @var boolean email template is enabled */
var $enabled;
/** @var array List of errors to display to the user */
var $errorMessages;
/** @var boolean whether or not to bcc the sender */
var $bccSender;
/** @var boolean Whether or not email fields are disabled */
var $addressFieldsEnabled;
/** @var array The list of parameters to be assigned to the template. */
var $params;
/**
* Constructor.
* @param $emailKey string unique identifier for the template
* @param $locale string locale of the template
* @param $includeSignature boolean optional
*/
function __construct($emailKey = null, $locale = null, $context = null, $includeSignature = true) {
parent::__construct();
$this->emailKey = isset($emailKey) ? $emailKey : null;
// If a context wasn't specified, use the current request.
$request = Application::get()->getRequest();
if ($context === null) $context = $request->getContext();
$this->includeSignature = $includeSignature;
// Use current user's locale if none specified
$this->locale = isset($locale) ? $locale : AppLocale::getLocale();
// Record whether or not to BCC the sender when sending message
$this->bccSender = $request->getUserVar('bccSender');
$this->addressFieldsEnabled = true;
if (isset($this->emailKey)) {
$emailTemplate = Services::get('emailTemplate')->getByKey($context ? $context->getId() : CONTEXT_SITE, $this->emailKey);
}
$userSig = '';
$user = defined('SESSION_DISABLE_INIT')?null:$request->getUser();
if ($user && $this->includeSignature) {
$userSig = $user->getLocalizedSignature();
if (!empty($userSig)) $userSig = "<br/>" . $userSig;
}
if (isset($emailTemplate)) {
$this->setSubject($emailTemplate->getData('subject', $this->locale));
$this->setBody($emailTemplate->getData('body', $this->locale) . $userSig);
$this->enabled = $emailTemplate->getData('enabled');
} else {
$this->setBody($userSig);
$this->enabled = true;
}
// Default "From" to user if available, otherwise site/context principal contact
if ($user) {
$this->setFrom($user->getEmail(), $user->getFullName());
} elseif (is_null($context) || is_null($context->getData('contactEmail'))) {
$site = $request->getSite();
$this->setFrom($site->getLocalizedContactEmail(), $site->getLocalizedContactName());
} else {
$this->setFrom($context->getData('contactEmail'), $context->getData('contactName'));
}
if ($context) {
$this->setSubject('[' . $context->getLocalizedAcronym() . '] ' . $this->getSubject());
}
$this->context = $context;
$this->params = array();
}
/**
* Disable or enable the address fields on the email form.
* NOTE: This affects the displayed form ONLY; if disabling the address
* fields, callers should manually clearAllRecipients and add/set
* recipients just prior to sending.
* @param $addressFieldsEnabled boolean
*/
function setAddressFieldsEnabled($addressFieldsEnabled) {
$this->addressFieldsEnabled = $addressFieldsEnabled;
}
/**
* Get the enabled/disabled state of address fields on the email form.
* @return boolean
*/
function getAddressFieldsEnabled() {
return $this->addressFieldsEnabled;
}
/**
* Check whether or not there were errors in the user input for this form.
* @return boolean true iff one or more error messages are stored.
*/
function hasErrors() {
return ($this->errorMessages != null);
}
/**
* Assigns values to e-mail parameters.
* @param $params array Associative array of variables to supply to the email template
*/
function assignParams($params = array()) {
$application = Application::get();
$request = $application->getRequest();
$site = $request->getSite();
if ($this->context) {
// Add context-specific variables
$dispatcher = $application->getDispatcher();
$params = array_merge([
'principalContactSignature' => htmlspecialchars($this->context->getData('contactName')),
'contextName' => htmlspecialchars($this->context->getLocalizedName()),
'contextUrl' => $dispatcher->url($request, ROUTE_PAGE, $this->context->getPath()),
], $params);
} else {
// No context available
$params = array_merge([
'principalContactSignature' => htmlspecialchars($site->getLocalizedContactName()),
], $params);
}
if (!defined('SESSION_DISABLE_INIT') && ($user = $request->getUser())) {
// Add user-specific variables
$params = array_merge([
'senderEmail' => htmlspecialchars($user->getEmail()),
'senderName' => htmlspecialchars($user->getFullName()),
], $params);
}
// Add some general variables
$params = array_merge([
'siteTitle' => htmlspecialchars($site->getLocalizedTitle()),
], $params);
$this->params = $params;
}
/**
* Returns true if the email template is enabled; false otherwise.
* @return boolean
*/
function isEnabled() {
return $this->enabled;
}
/**
* Send the email.
* @return boolean false if there was a problem sending the email
*/
function send() {
if (isset($this->context)) {
$signature = $this->context->getData('emailSignature');
if (strstr($this->getBody(), '{$templateSignature}') === false) {
$this->setBody($this->getBody() . "<br/>" . $signature);
} else {
$this->setBody(str_replace('{$templateSignature}', $signature, $this->getBody()));
}
$envelopeSender = $this->context->getData('envelopeSender');
if (!empty($envelopeSender) && Config::getVar('email', 'allow_envelope_sender')) $this->setEnvelopeSender($envelopeSender);
}
$request = Application::get()->getRequest();
$user = defined('SESSION_DISABLE_INIT')?null:$request->getUser();
if ($user && $this->bccSender) {
$this->addBcc($user->getEmail(), $user->getFullName());
}
// Replace variables in message with values
$this->replaceParams();
return parent::send();
}
/**
* Replace template variables in the message body.
* @param $params array Parameters to assign (augments anything provided via setParams)
*/
function replaceParams() {
$subject = $this->getSubject();
$body = $this->getBody();
foreach ($this->params as $key => $value) {
if (!is_object($value)) {
// $value is checked to identify URL pattern
if (filter_var($value, FILTER_VALIDATE_URL) != false) {
$body = $this->manageURLValues($body, $key, $value);
} else {
$body = str_replace('{$' . $key . '}', $value, $body);
}
}
$subject = str_replace('{$' . $key . '}', $value, $subject);
}
$this->setSubject($subject);
$this->setBody($body);
}
/**
* Assigns user-specific values to email parameters, sends
* the email, then clears those values.
* @param $params array Associative array of variables to supply to the email template
* @return boolean false if there was a problem sending the email
*/
function sendWithParams($params) {
$savedHeaders = $this->getHeaders();
$savedSubject = $this->getSubject();
$savedBody = $this->getBody();
$this->assignParams($params);
$ret = $this->send();
$this->setHeaders($savedHeaders);
$this->setSubject($savedSubject);
$this->setBody($savedBody);
return $ret;
}
/**
* Clears the recipient, cc, and bcc lists.
* @param $clearHeaders boolean if true, also clear headers
* @return void
*/
function clearRecipients($clearHeaders = true) {
$this->setData('recipients', null);
$this->setData('ccs', null);
$this->setData('bccs', null);
if ($clearHeaders) {
$this->setData('headers', null);
}
}
/**
* Finds and changes appropriately URL valued template parameter keys.
* @param $targetString string The string that contains the original {$key}s template variables
* @param $key string The key we are looking for, and has an URL as its $value
* @param $value string The value of the $key
* @return string the $targetString replaced appropriately
*/
function manageURLValues($targetString, $key, $value) {
// If the value is URL, we need to find if $key resides in a href={$...} pattern.
preg_match_all('/=[\\\'"]{\\$' . preg_quote($key) . '}/', $targetString, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
// if we find some ={$...} occurences of the $key in the email body, then we need to replace them with
// the corresponding value
if ($matches) {
// We make the change backwords (last offset replaced first) so that smaller offsets correctly mark the string they supposed to.
for($i = count($matches)-1; $i >= 0; $i--) {
$match = $matches[$i][0];
$targetString = substr_replace($targetString, str_replace('{$' . $key . '}', $value, $match[0]), $match[1], strlen($match[0]));
}
}
// all the ={$...} patterns have been replaced - now we can change the remaining URL $keys with the following pattern
$value = "<a href='$value' class='$key-style-class'>$value</a>";
$targetString = str_replace('{$' . $key . '}', $value, $targetString);
return $targetString;
}
}
|