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 $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('

{EMAIL}

', $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 []; } }