<?php
/**
* @file classes/mail/traits/Unsubscribe.php
*
* Copyright (c) 2014-2022 Simon Fraser University
* Copyright (c) 2000-2022 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class Unsubscribe
*
* @ingroup mail_traits
*
* @brief trait to embed footer with unsubscribe link to notification emails
*/
namespace PKP\mail\traits;
use APP\core\Application;
use APP\mail\variables\ContextEmailVariable;
use APP\notification\Notification;
use APP\notification\NotificationManager;
use Exception;
use Illuminate\Mail\Mailables\Headers;
use PKP\mail\Mailable;
use PKP\mail\variables\ContextEmailVariable as PKPContextEmailVariable;
trait Unsubscribe
{
protected static string $unsubscribeUrl = 'unsubscribeUrl';
// Notification to generate unsubscribe link
protected Notification $notification;
// Locale key used by default in the footer if none is specified by Mailable::setupUnsubscribeFooter()
protected string $defaultUnsubscribeLocaleKey = 'emails.footer.unsubscribe';
/**
* @var string[] template variables required for the unsubscribe footer
*/
protected static array $requiredVariables = [PKPContextEmailVariable::class];
abstract public function addData(array $data): Mailable;
abstract public function getVariables(): array;
/**
* Use this public method to set footer for this email
*/
public function allowUnsubscribe(Notification $notification): self
{
$this->notification = $notification;
if (!$this->hasRequiredVariables()) {
throw new Exception(
'Mailable should include the following template variables: ' .
implode(',', static::getRequiredVariables())
);
}
return $this;
}
/**
* Setup footer with unsubscribe link if notification is deliberately set with self::allowUnsubscribe()
*
* @param null|mixed $localeKey
*/
protected function setupUnsubscribeFooter(string $locale, $context, $localeKey = null): void
{
if (!isset($this->notification)) {
return;
}
$this->footer = $this->renameContextVariables($this->setFooterText($locale, $localeKey));
$notificationManager = new NotificationManager(); /** @var NotificationManager $notificationManager */
$request = Application::get()->getRequest();
$this->addData([
self::$unsubscribeUrl => $notificationManager->getUnsubscribeNotificationUrl(
$request,
$this->notification,
$context
),
]);
}
/**
* Adds unsubscribe headers, see pkp/pkp-lib#6627
*/
public function headers(): Headers
{
$unsubscribeUrl = $this->viewData[self::$unsubscribeUrl] ?? null;
return new Headers(
null,
[],
$unsubscribeUrl ? [
'List-Unsubscribe-Post' => 'List-Unsubscribe=One-Click',
'List-Unsubscribe' => '<' . $unsubscribeUrl . '>',
] : []
);
}
/**
* @return bool whether mailable contains variables requires for the footer
*/
protected function hasRequiredVariables(): bool
{
$included = [];
$requiredVariables = static::getRequiredVariables();
foreach ($requiredVariables as $requiredVariable) {
foreach ($this->getVariables() as $variable) {
if (is_a($variable, $requiredVariable, true)) {
$included[] = $requiredVariable;
break;
}
}
}
return count($included) === count($requiredVariables);
}
/**
* Replace email template variables in the locale string, so they correspond to the application,
* e.g., contextName => journalName/pressName/serverName
*/
protected function renameContextVariables(string $footer): string
{
$map = [
'{$' . PKPContextEmailVariable::CONTEXT_NAME . '}' => '{$' . ContextEmailVariable::CONTEXT_NAME . '}',
'{$' . PKPContextEmailVariable::CONTEXT_URL . '}' => '{$' . ContextEmailVariable::CONTEXT_URL . '}',
'{$' . PKPContextEmailVariable::CONTEXT_SIGNATURE . '}' => '{$' . ContextEmailVariable::CONTEXT_SIGNATURE . '}',
];
return str_replace(array_keys($map), array_values($map), $footer);
}
/**
* Set the message to be displayed in the footer
*/
protected function setFooterText(string $locale, string $localeKey = null): string
{
if (is_null($localeKey)) {
$localeKey = $this->defaultUnsubscribeLocaleKey;
}
return __($localeKey, [], $locale);
}
protected static function getRequiredVariables(): array
{
return static::$requiredVariables;
}
}
|