<?php declare(strict_types=1);
namespace MoorlForms\Core\Subscriber;
use MoorlForms\Core\Event\SendMailEvent;
use MoorlForms\Core\Service\FbService;
use Shopware\Core\Checkout\Order\OrderEntity;
use Shopware\Core\Content\Flow\Events\FlowSendMailActionEvent;
use Shopware\Core\Content\Mail\Service\AbstractMailService;
use Shopware\Core\Content\MailTemplate\Event\MailSendSubscriberBridgeEvent;
use Shopware\Core\Content\MailTemplate\Exception\MailEventConfigurationException;
use Shopware\Core\Content\MailTemplate\MailTemplateEntity;
use Shopware\Core\Content\Media\MediaCollection;
use Shopware\Core\Content\Media\MediaService;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\Event\OrderAware;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Contracts\EventDispatcher\Event;
use Shopware\Core\Framework\Event\EventData\EventDataType;
use Shopware\Core\Framework\Validation\DataBag\DataBag;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class SendMailSubscriber implements EventSubscriberInterface
{
public const MAIL_TEMPLATE_TYPE = 'moorl_fb';
private AbstractMailService $mailService;
private EntityRepositoryInterface $mailTemplateRepository;
private MediaService $mediaService;
private FbService $fbService;
private SystemConfigService $systemConfigService;
public function __construct(
AbstractMailService $mailService,
EntityRepositoryInterface $mailTemplateRepository,
MediaService $mediaService,
FbService $fbService,
SystemConfigService $systemConfigService
)
{
$this->mailService = $mailService;
$this->mailTemplateRepository = $mailTemplateRepository;
$this->mediaService = $mediaService;
$this->fbService = $fbService;
$this->systemConfigService = $systemConfigService;
}
public static function getSubscribedEvents(): array
{
return [
FlowSendMailActionEvent::class => 'addAttachments',
MailSendSubscriberBridgeEvent::class => 'addAttachments',
SendMailEvent::class => 'sendMail',
];
}
/**
* Enrich attachments to BusinessEvent or FlowEvent
*
* @param $event
*/
public function addAttachments($event): void
{
if ($event instanceof FlowSendMailActionEvent) {
$mailEvent = $event->getFlowEvent()->getEvent();
} else {
$mailEvent = $event->getBusinessEvent()->getEvent();
}
$mediaCollection = new MediaCollection();
/* Look for attachments in order and line items */
if ($this->systemConfigService->get('MoorlForms.config.orderSendAttachments')) {
if ($mailEvent instanceof OrderAware) {
/** @var OrderEntity $order */
$order = $mailEvent->getOrder();
$this->fbService->enrichAttachmentsFromEntity($mediaCollection, $order, $event->getContext());
foreach ($order->getLineItems() as $lineItem) {
$this->fbService->enrichAttachmentsFromEntity($mediaCollection, $lineItem, $event->getContext());
}
}
}
$attachments = $event->getDataBag()->get('binAttachments', []);
foreach ($mediaCollection as $mediaEntity) {
$attachments[] = $this->mediaService->getAttachment($mediaEntity, $event->getContext());
}
$event->getDataBag()->set('binAttachments', $attachments);
}
/**
* Send mail without BusinessEvent or FlowEvent
*
* @param SendMailEvent $event
* @throws MailEventConfigurationException
*/
public function sendMail(SendMailEvent $event): void
{
$form = $event->getForm();
$mailTemplate = $this->getMailTemplate($event->getTemplateId(), $event->getContext());
if (!$form || !$mailTemplate) {
return;
}
$data = new DataBag();
$data->set('recipients', $event->getMailStruct()->getRecipients());
if ($event->getReplyTo()) {
$data->set('replyTo', $event->getReplyTo());
}
$data->set('senderName', $mailTemplate->getTranslation('senderName'));
$data->set('salesChannelId', $event->getSalesChannelId());
$data->set('templateId', $mailTemplate->getId());
$data->set('customFields', $mailTemplate->getCustomFields());
$data->set('contentHtml', $mailTemplate->getTranslation('contentHtml'));
$data->set('contentPlain', $mailTemplate->getTranslation('contentPlain'));
$data->set('subject', $mailTemplate->getTranslation('subject'));
$data->set('mediaIds', []);
$attachments = $form->getAttachments();
if ($mailTemplate->getMedia()) {
foreach ($mailTemplate->getMedia() as $mailTemplateMedia) {
if (!$mailTemplateMedia->getMedia()) {
continue;
}
if ($mailTemplateMedia->getLanguageId() && $mailTemplateMedia->getLanguageId() !== $event->getContext()->getLanguageId()) {
continue;
}
$attachments[] = $this->mediaService->getAttachment($mailTemplateMedia->getMedia(), $event->getContext());
}
}
if (!empty($attachments)) {
$data->set('binAttachments', $attachments);
}
$this->mailService->send(
$data->all(),
$event->getContext(),
$this->getTemplateData($event)
);
}
private function getMailTemplate(?string $mailTemplateId, Context $context): MailTemplateEntity
{
$mailTemplate = null;
if ($mailTemplateId) {
$criteria = new Criteria([$mailTemplateId]);
$criteria->addAssociation('media.media');
$criteria->setLimit(1);
$mailTemplate = $this->mailTemplateRepository->search($criteria, $context)->first();
}
if (!$mailTemplate) {
$criteria = new Criteria();
$criteria->addAssociation('media.media');
$criteria->setLimit(1);
$criteria->addFilter(new EqualsFilter('mailTemplateType.technicalName', self::MAIL_TEMPLATE_TYPE));
$mailTemplate = $this->mailTemplateRepository->search($criteria, $context)->first();
}
return $mailTemplate;
}
/**
* @throws MailEventConfigurationException
*/
private function getTemplateData(SendMailEvent $event): array
{
$data = [];
/* @var EventDataType $item */
foreach (array_keys($event::getAvailableData()->toArray()) as $key) {
$getter = 'get' . ucfirst($key);
if (method_exists($event, $getter)) {
$data[$key] = $event->$getter();
} else {
throw new MailEventConfigurationException('Data for ' . $key . ' not available.', get_class($event));
}
}
return $data;
}
}