Files
2025-08-02 16:30:27 +02:00

434 lines
12 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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 emailů';
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 [];
}
}