vendor/shopware/core/Content/MailTemplate/Subscriber/MailSendSubscriber.php line 101

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Content\MailTemplate\Subscriber;
  3. use Psr\Log\LoggerInterface;
  4. use Shopware\Core\Checkout\Document\DocumentService;
  5. use Shopware\Core\Content\Mail\Service\AbstractMailService;
  6. use Shopware\Core\Content\MailTemplate\Event\MailSendSubscriberBridgeEvent;
  7. use Shopware\Core\Content\MailTemplate\Exception\MailEventConfigurationException;
  8. use Shopware\Core\Content\MailTemplate\Exception\SalesChannelNotFoundException;
  9. use Shopware\Core\Content\MailTemplate\MailTemplateActions;
  10. use Shopware\Core\Content\MailTemplate\MailTemplateEntity;
  11. use Shopware\Core\Content\Media\MediaService;
  12. use Shopware\Core\Framework\Adapter\Translation\Translator;
  13. use Shopware\Core\Framework\Context;
  14. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  17. use Shopware\Core\Framework\Event\BusinessEvent;
  18. use Shopware\Core\Framework\Event\MailActionInterface;
  19. use Shopware\Core\Framework\Feature;
  20. use Shopware\Core\Framework\Log\Package;
  21. use Shopware\Core\Framework\Validation\DataBag\DataBag;
  22. use Shopware\Core\System\Locale\LanguageLocaleCodeProvider;
  23. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  24. use Symfony\Contracts\EventDispatcher\Event;
  25. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  26. /**
  27. * @deprecated tag:v6.5.0 - reason:remove-subscriber - Will be removed in v6.5.0 Use SendMailAction instead
  28. */
  29. #[Package('sales-channel')]
  30. class MailSendSubscriber implements EventSubscriberInterface
  31. {
  32. public const ACTION_NAME = MailTemplateActions::MAIL_TEMPLATE_MAIL_SEND_ACTION;
  33. public const MAIL_CONFIG_EXTENSION = 'mail-attachments';
  34. private EntityRepositoryInterface $mailTemplateRepository;
  35. private MediaService $mediaService;
  36. private EntityRepositoryInterface $mediaRepository;
  37. private DocumentService $documentService;
  38. private EntityRepositoryInterface $documentRepository;
  39. private LoggerInterface $logger;
  40. private AbstractMailService $emailService;
  41. private EventDispatcherInterface $eventDispatcher;
  42. private EntityRepositoryInterface $mailTemplateTypeRepository;
  43. private Translator $translator;
  44. private LanguageLocaleCodeProvider $languageLocaleProvider;
  45. /**
  46. * @internal
  47. */
  48. public function __construct(
  49. AbstractMailService $emailService,
  50. EntityRepositoryInterface $mailTemplateRepository,
  51. MediaService $mediaService,
  52. EntityRepositoryInterface $mediaRepository,
  53. EntityRepositoryInterface $documentRepository,
  54. DocumentService $documentService,
  55. LoggerInterface $logger,
  56. EventDispatcherInterface $eventDispatcher,
  57. EntityRepositoryInterface $mailTemplateTypeRepository,
  58. Translator $translator,
  59. LanguageLocaleCodeProvider $languageLocaleProvider
  60. ) {
  61. $this->mailTemplateRepository = $mailTemplateRepository;
  62. $this->mediaService = $mediaService;
  63. $this->mediaRepository = $mediaRepository;
  64. $this->documentRepository = $documentRepository;
  65. $this->documentService = $documentService;
  66. $this->logger = $logger;
  67. $this->emailService = $emailService;
  68. $this->eventDispatcher = $eventDispatcher;
  69. $this->mailTemplateTypeRepository = $mailTemplateTypeRepository;
  70. $this->translator = $translator;
  71. $this->languageLocaleProvider = $languageLocaleProvider;
  72. }
  73. public static function getSubscribedEvents(): array
  74. {
  75. return [
  76. self::ACTION_NAME => 'sendMail',
  77. ];
  78. }
  79. /**
  80. * @throws MailEventConfigurationException
  81. * @throws SalesChannelNotFoundException
  82. * @throws InconsistentCriteriaIdsException
  83. */
  84. public function sendMail(Event $event): void
  85. {
  86. if (Feature::isActive('FEATURE_NEXT_17858')) {
  87. return;
  88. }
  89. if (!$event instanceof BusinessEvent) {
  90. return;
  91. }
  92. $mailEvent = $event->getEvent();
  93. $extension = $event->getContext()->getExtension(self::MAIL_CONFIG_EXTENSION);
  94. if (!$extension instanceof MailSendSubscriberConfig) {
  95. $extension = new MailSendSubscriberConfig(false, [], []);
  96. }
  97. if ($extension->skip()) {
  98. return;
  99. }
  100. if (!$mailEvent instanceof MailActionInterface) {
  101. throw new MailEventConfigurationException('Not a instance of MailActionInterface', \get_class($mailEvent));
  102. }
  103. $config = $event->getConfig();
  104. if (!isset($config['mail_template_id'])) {
  105. return;
  106. }
  107. $mailTemplate = $this->getMailTemplate($config['mail_template_id'], $event->getContext());
  108. if ($mailTemplate === null) {
  109. return;
  110. }
  111. $injectedTranslator = $this->injectTranslator($mailEvent);
  112. $data = new DataBag();
  113. $recipients = $mailEvent->getMailStruct()->getRecipients();
  114. if (isset($config['recipients']) && !empty($config['recipients'])) {
  115. $recipients = $config['recipients'];
  116. }
  117. $data->set('recipients', $recipients);
  118. $data->set('senderName', $mailTemplate->getTranslation('senderName'));
  119. $data->set('salesChannelId', $mailEvent->getSalesChannelId());
  120. $data->set('templateId', $mailTemplate->getId());
  121. $data->set('customFields', $mailTemplate->getCustomFields());
  122. $data->set('contentHtml', $mailTemplate->getTranslation('contentHtml'));
  123. $data->set('contentPlain', $mailTemplate->getTranslation('contentPlain'));
  124. $data->set('subject', $mailTemplate->getTranslation('subject'));
  125. $data->set('mediaIds', []);
  126. $attachments = $this->buildAttachments($event, $mailTemplate, $extension);
  127. if (!empty($attachments)) {
  128. $data->set('binAttachments', $attachments);
  129. }
  130. $this->eventDispatcher->dispatch(new MailSendSubscriberBridgeEvent($data, $mailTemplate, $event));
  131. if ($data->has('templateId')) {
  132. try {
  133. $this->mailTemplateTypeRepository->update([[
  134. 'id' => $mailTemplate->getMailTemplateTypeId(),
  135. 'templateData' => $this->getTemplateData($mailEvent),
  136. ]], $mailEvent->getContext());
  137. } catch (\Throwable $e) {
  138. // Dont throw errors if this fails // Fix with NEXT-15475
  139. }
  140. }
  141. try {
  142. $this->emailService->send(
  143. $data->all(),
  144. $event->getContext(),
  145. $this->getTemplateData($mailEvent)
  146. );
  147. $writes = array_map(static function ($id) {
  148. return ['id' => $id, 'sent' => true];
  149. }, $extension->getDocumentIds());
  150. if (!empty($writes)) {
  151. $this->documentRepository->update($writes, $event->getContext());
  152. }
  153. } catch (\Exception $e) {
  154. $this->logger->error(
  155. "Could not send mail:\n"
  156. . $e->getMessage() . "\n"
  157. . 'Error Code:' . $e->getCode() . "\n"
  158. . "Template data: \n"
  159. . json_encode($data->all()) . "\n"
  160. );
  161. }
  162. if ($injectedTranslator) {
  163. $this->translator->resetInjection();
  164. }
  165. }
  166. private function getMailTemplate(string $id, Context $context): ?MailTemplateEntity
  167. {
  168. $criteria = new Criteria([$id]);
  169. $criteria->addAssociation('media.media');
  170. $criteria->setLimit(1);
  171. return $this->mailTemplateRepository
  172. ->search($criteria, $context)
  173. ->first();
  174. }
  175. /**
  176. * @throws MailEventConfigurationException
  177. */
  178. private function getTemplateData(MailActionInterface $event): array
  179. {
  180. $data = [];
  181. foreach (array_keys($event::getAvailableData()->toArray()) as $key) {
  182. $getter = 'get' . ucfirst($key);
  183. if (method_exists($event, $getter)) {
  184. $data[$key] = $event->$getter();
  185. } else {
  186. throw new MailEventConfigurationException('Data for ' . $key . ' not available.', \get_class($event));
  187. }
  188. }
  189. return $data;
  190. }
  191. private function buildAttachments(BusinessEvent $event, MailTemplateEntity $mailTemplate, MailSendSubscriberConfig $config): array
  192. {
  193. $attachments = [];
  194. if ($mailTemplate->getMedia() !== null) {
  195. foreach ($mailTemplate->getMedia() as $mailTemplateMedia) {
  196. if ($mailTemplateMedia->getMedia() === null) {
  197. continue;
  198. }
  199. if ($mailTemplateMedia->getLanguageId() !== null && $mailTemplateMedia->getLanguageId() !== $event->getContext()->getLanguageId()) {
  200. continue;
  201. }
  202. $attachments[] = $this->mediaService->getAttachment(
  203. $mailTemplateMedia->getMedia(),
  204. $event->getContext()
  205. );
  206. }
  207. }
  208. if (!empty($config->getMediaIds())) {
  209. $entities = $this->mediaRepository->search(new Criteria($config->getMediaIds()), $event->getContext());
  210. foreach ($entities as $media) {
  211. $attachments[] = $this->mediaService->getAttachment($media, $event->getContext());
  212. }
  213. }
  214. if (!empty($config->getDocumentIds())) {
  215. $criteria = new Criteria($config->getDocumentIds());
  216. $criteria->addAssociation('documentMediaFile');
  217. $criteria->addAssociation('documentType');
  218. $entities = $this->documentRepository->search($criteria, $event->getContext());
  219. foreach ($entities as $document) {
  220. $document = $this->documentService->getDocument($document, $event->getContext());
  221. $attachments[] = [
  222. 'content' => $document->getFileBlob(),
  223. 'fileName' => $document->getFilename(),
  224. 'mimeType' => $document->getContentType(),
  225. ];
  226. }
  227. }
  228. return $attachments;
  229. }
  230. private function injectTranslator(MailActionInterface $event): bool
  231. {
  232. if ($event->getSalesChannelId() === null) {
  233. return false;
  234. }
  235. if ($this->translator->getSnippetSetId() !== null) {
  236. return false;
  237. }
  238. $this->translator->injectSettings(
  239. $event->getSalesChannelId(),
  240. $event->getContext()->getLanguageId(),
  241. $this->languageLocaleProvider->getLocaleForLanguageId($event->getContext()->getLanguageId()),
  242. $event->getContext()
  243. );
  244. return true;
  245. }
  246. }