434 lines
12 KiB
PHP
434 lines
12 KiB
PHP
<?php
|
||
|
||
namespace KupShop\KupShopBundle\Email;
|
||
|
||
use KupShop\ContentBundle\Entity\Placeholder;
|
||
use KupShop\I18nBundle\Translations\EmailsTranslation;
|
||
use KupShop\KupShopBundle\Config;
|
||
use KupShop\KupShopBundle\Context\LanguageContext;
|
||
use KupShop\KupShopBundle\Event\EmailEvent;
|
||
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
|
||
use KupShop\KupShopBundle\Util\Mail\EmailLocator;
|
||
use KupShop\KupShopBundle\Util\StringUtil;
|
||
use KupShop\OrderingBundle\Attachment\AttachmentInterface;
|
||
use KupShop\OrderingBundle\Exception\IgnoreAttachmentException;
|
||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||
|
||
class BaseEmail implements EmailInterface
|
||
{
|
||
protected static $name = 'Šablona e‑mailů';
|
||
protected static $type = 'BASIC_TEMPLATE';
|
||
protected static $priority = 100;
|
||
protected static $group = EmailGroupTypeEnum::OTHER;
|
||
|
||
protected $subject = '';
|
||
protected $template = 'email/email_basic_template.tpl'; // Default template for email content (body)
|
||
protected $baseTemplate = 'email/other.tpl'; // Default template for complete email rendering (header, body, footer, ...)
|
||
protected $body = '';
|
||
|
||
protected $emails = [];
|
||
|
||
/** @var LanguageContext */
|
||
protected $languageContext;
|
||
|
||
/** @var Placeholder[] */
|
||
private array $placeholders = [];
|
||
|
||
protected $enabled;
|
||
protected $defaultEnabled = 'Y';
|
||
|
||
public function __construct(LanguageContext $languageContext)
|
||
{
|
||
$this->languageContext = $languageContext;
|
||
}
|
||
|
||
/** @var EventDispatcherInterface */
|
||
private $eventDispatcher;
|
||
|
||
/** @var EmailLocator */
|
||
protected $emailLocator;
|
||
|
||
/**
|
||
* @required
|
||
*/
|
||
public function setEventDispatcher(EventDispatcherInterface $eventDispatcher)
|
||
{
|
||
$this->eventDispatcher = $eventDispatcher;
|
||
}
|
||
|
||
/**
|
||
* @required
|
||
*/
|
||
public function setEmailLocator(EmailLocator $emailLocator): void
|
||
{
|
||
$this->emailLocator = $emailLocator;
|
||
}
|
||
|
||
public static function getName(): string
|
||
{
|
||
return translate('email_types', 'emails')[static::$type] ?? static::$name;
|
||
}
|
||
|
||
public static function getType(): string
|
||
{
|
||
return static::$type;
|
||
}
|
||
|
||
public static function getGroup(): string
|
||
{
|
||
return static::$group->value;
|
||
}
|
||
|
||
public static function getPriority()
|
||
{
|
||
return static::$priority;
|
||
}
|
||
|
||
public static function attachmentsAllowed()
|
||
{
|
||
return false;
|
||
}
|
||
|
||
public static function isAllowed()
|
||
{
|
||
return true;
|
||
}
|
||
|
||
public function getTemplate()
|
||
{
|
||
return $this->template;
|
||
}
|
||
|
||
public function getSubject(): string
|
||
{
|
||
return $this->subject;
|
||
}
|
||
|
||
public function getBody()
|
||
{
|
||
if (!$this->body) {
|
||
if (!empty($this->template)) {
|
||
/** Smarty je použit kvůli předefinovávání šablon */
|
||
$smarty = createSmarty(true, true, true);
|
||
$this->body = $smarty->fetch($this->template);
|
||
}
|
||
}
|
||
|
||
return $this->body;
|
||
}
|
||
|
||
public function getDefaultEmail(): array
|
||
{
|
||
$dbcfg = \Settings::getDefault();
|
||
|
||
$email = [
|
||
'type' => self::getType(),
|
||
'email' => $dbcfg->order_shopkeeper_mail,
|
||
'body' => $this->getBody(),
|
||
'subject' => empty($this->subject) ? $dbcfg->shop_firm_name : $this->subject,
|
||
'attachments' => null,
|
||
'enabled' => $this->defaultEnabled,
|
||
];
|
||
|
||
return $email;
|
||
}
|
||
|
||
public function setEnabled(?bool $enabled)
|
||
{
|
||
$this->enabled = $enabled;
|
||
}
|
||
|
||
public function isEnabled(): bool
|
||
{
|
||
if (!isset($this->enabled)) {
|
||
$template = $this->getEmailTemplate();
|
||
$enabled = $template['enabled'] ?? 'N';
|
||
$this->enabled = ($enabled == 'Y');
|
||
}
|
||
|
||
return $this->enabled;
|
||
}
|
||
|
||
public function getEmailTemplate($languageID = null): array
|
||
{
|
||
if (!$languageID) {
|
||
$languageID = $this->languageContext->getActiveId();
|
||
}
|
||
|
||
if (empty($this->emails[$languageID])) {
|
||
$template = sqlQueryBuilder()
|
||
->select('e.*')
|
||
->from('emails', 'e')
|
||
->where('e.type=:type')
|
||
->setParameter('type', self::getType())
|
||
->andWhere(
|
||
\Query\Translation::coalesceTranslatedFields(
|
||
EmailsTranslation::class,
|
||
null,
|
||
$languageID
|
||
)
|
||
)
|
||
->orderBy('id', 'DESC')
|
||
->execute()
|
||
->fetch();
|
||
if ($template) {
|
||
$this->emails[$languageID] = $template;
|
||
} else {
|
||
$this->emails[$languageID] = $this->getDefaultEmail();
|
||
}
|
||
}
|
||
|
||
return $this->emails[$languageID];
|
||
}
|
||
|
||
public function getEmail($replacements = []): array
|
||
{
|
||
$template = $this->getEmailTemplate();
|
||
if (!$this->isEnabled()) {
|
||
return $template;
|
||
}
|
||
|
||
foreach ($this->emailLocator->getEmailRegisters() as $register) {
|
||
$register->applyPlaceholders($this);
|
||
}
|
||
|
||
$message = $this->renderEmail($template);
|
||
$message['body'] = $this->replacePlaceholders($message['body'], $replacements);
|
||
$message['subject'] = StringUtil::htmlToCleanText($this->replacePlaceholders($message['subject'], $replacements));
|
||
|
||
return $message;
|
||
}
|
||
|
||
public function getSMSText(array $replacements = []): string
|
||
{
|
||
foreach ($this->emailLocator->getEmailRegisters() as $register) {
|
||
$register->applyPlaceholders($this);
|
||
}
|
||
|
||
return $this->replacePlaceholders($this->getEmailTemplate()['sms'] ?? '', $replacements);
|
||
}
|
||
|
||
public function sendEmail($message)
|
||
{
|
||
if (!$this->isEnabled()) {
|
||
return false;
|
||
}
|
||
|
||
if (empty($message['to'])) {
|
||
return false;
|
||
}
|
||
|
||
$event = $this->eventDispatcher->dispatch(new EmailEvent($message, $this), EmailEvent::SEND);
|
||
|
||
return $event->getMessageId();
|
||
}
|
||
|
||
public function getAttachments($template): array
|
||
{
|
||
return [];
|
||
}
|
||
|
||
public function getEntityPlaceholders(): array
|
||
{
|
||
return $this->placeholders;
|
||
}
|
||
|
||
/**
|
||
* @param callable(): iterable<AttachmentInterface> $generatorFn
|
||
*/
|
||
protected function renderAttachments(callable $generatorFn): array
|
||
{
|
||
$result = [];
|
||
|
||
foreach ($generatorFn() as $attachment) {
|
||
try {
|
||
$attachmentData = $attachment->getAttachment();
|
||
|
||
$result[] = [
|
||
$attachmentData['attachment_type'] => $attachmentData['attachment'],
|
||
'filename' => $attachmentData['filename'],
|
||
'type' => $attachment::getType(),
|
||
];
|
||
} catch (\Throwable $e) {
|
||
// throw exception in local development so error is visible for us
|
||
if (isLocalDevelopment()) {
|
||
throw $e;
|
||
}
|
||
|
||
// we will ignore error if exception is `IgnoreAttachmentException`
|
||
if ($e instanceof IgnoreAttachmentException) {
|
||
continue;
|
||
}
|
||
|
||
// capture to sentry
|
||
\Sentry\captureException($e);
|
||
}
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
|
||
public function testEmail(): array
|
||
{
|
||
$this->setEnabled(true);
|
||
$message = $this->getEmail();
|
||
$this->setEnabled(null);
|
||
|
||
return $message;
|
||
}
|
||
|
||
/**
|
||
* @param array $data
|
||
*/
|
||
public function renderEmail($message, $data = [], $base_template = null): array
|
||
{
|
||
$template = $this->getBasicTemplate();
|
||
$template['body'] = $message['body'];
|
||
$template['subject'] = $message['subject'];
|
||
if (!empty($message['email'])) {
|
||
$template['email'] = $message['email'];
|
||
}
|
||
if ($microdata = $this->getMicrodata()) {
|
||
$template['microdata'] = json_encode($microdata, JSON_NUMERIC_CHECK | JSON_HEX_APOS | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
|
||
}
|
||
|
||
$smarty = createSmarty(false, true);
|
||
$smarty->assign(array_merge([
|
||
'body' => $template,
|
||
], $data));
|
||
|
||
$body = $smarty->fetch(is_null($base_template) ? $this->baseTemplate : "email/{$base_template}");
|
||
|
||
return ['body' => $body, 'subject' => $template['subject'], 'from' => $template['email'], 'type' => self::getType(), 'attachments' => []];
|
||
}
|
||
|
||
public function renderOnlyBody($message, $data = []): string
|
||
{
|
||
return trim(
|
||
createSmarty(false, true)
|
||
->assign(array_merge([
|
||
'body' => $message['template'],
|
||
'extend_template' => 'email/only_body.tpl',
|
||
], $data))
|
||
->fetch($this->baseTemplate)
|
||
);
|
||
}
|
||
|
||
/**
|
||
* @return array
|
||
*/
|
||
public function getBasicTemplate($languageID = null)
|
||
{
|
||
$template = (new BaseEmail($this->languageContext))->getEmailTemplate($languageID);
|
||
$parts = explode('<p>{EMAIL}</p>', $template['body']);
|
||
|
||
if (count($parts) == 1) {
|
||
$parts = explode('{EMAIL}', $template['body']);
|
||
}
|
||
|
||
if (count($parts) < 2) {
|
||
$parts[1] = '';
|
||
}
|
||
$template_email = array_combine(['header', 'footer'], $parts);
|
||
$template_email['email'] = $template['email'];
|
||
|
||
return $template_email;
|
||
}
|
||
|
||
protected function replacePlaceholders(string $text, array $replacements = []): string
|
||
{
|
||
$loop = 0;
|
||
while (preg_match('/{(.+?)}/', $text) && $loop++ < 5) {
|
||
$text = replacePlaceholders($text, $replacements, [$this, 'replacePlaceholdersItem']);
|
||
}
|
||
|
||
return $text;
|
||
}
|
||
|
||
public static function getPlaceholders()
|
||
{
|
||
$cfg = Config::get();
|
||
|
||
$placeholders[self::$type] = [
|
||
'DATUM' => [
|
||
'text' => translate('CurrentDate', 'emails'),
|
||
],
|
||
'CAS' => [
|
||
'text' => translate('CurrentTime', 'emails'),
|
||
],
|
||
'WEB' => [
|
||
'text' => translate('CompleteURL', 'emails').' - '.$cfg['Addr']['full'],
|
||
],
|
||
'WEB_NAZEV' => [
|
||
'text' => translate('NameURL', 'emails').' - '.rtrim($cfg['Addr']['print'], '/'),
|
||
],
|
||
'PODPIS' => [
|
||
'text' => translate('signature', 'emails'),
|
||
],
|
||
];
|
||
|
||
return $placeholders;
|
||
}
|
||
|
||
public function replacePlaceholdersItem($placeholder)
|
||
{
|
||
if ($this->placeholders[$placeholder] ?? false) {
|
||
return $this->placeholders[$placeholder]->getValue();
|
||
}
|
||
|
||
$cfg = Config::get();
|
||
switch ($placeholder) {
|
||
case 'DATUM':
|
||
return date('d.\&\n\b\s\p\;m.\&\n\b\s\p\;Y');
|
||
case 'CAS':
|
||
return date('H:i:s');
|
||
case 'WEB':
|
||
return $cfg['Addr']['full'];
|
||
case 'WEB_NAZEV':
|
||
return rtrim($cfg['Addr']['print'], '/');
|
||
case 'PODPIS':
|
||
$admin = getAdminUser();
|
||
if ($admin['data']['signature'] ?? null) {
|
||
return $admin['data']['signature'];
|
||
}
|
||
$settings = \Settings::getDefault();
|
||
if ($settings['email_default_signature']['signature'] ?? null) {
|
||
return $settings['email_default_signature']['signature'];
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
public function addPlaceholder(string $placeholder, callable $renderer, string $description): void
|
||
{
|
||
$this->placeholders[$placeholder] = new Placeholder($placeholder, $description, $renderer);
|
||
}
|
||
|
||
public function __wakeup()
|
||
{
|
||
$this->eventDispatcher = ServiceContainer::getService('event_dispatcher');
|
||
$this->languageContext = ServiceContainer::getService(LanguageContext::class);
|
||
$this->emailLocator = ServiceContainer::getService(EmailLocator::class);
|
||
}
|
||
|
||
public function __sleep()
|
||
{
|
||
$vars = array_keys(get_object_vars($this));
|
||
|
||
return array_diff($vars, ['eventDispatcher', 'languageContext', 'emailLocator', 'placeholders', 'emails']);
|
||
}
|
||
|
||
public function getTestType(): ?string
|
||
{
|
||
return null;
|
||
}
|
||
|
||
public function getMicrodata(): array
|
||
{
|
||
return [];
|
||
}
|
||
}
|