Passed
Push — master ( 72b2aa...c8dd73 )
by Christian
13:52 queued 11s
created

MailSendSubscriber::sendMail()   C

Complexity

Conditions 13
Paths 104

Size

Total Lines 87
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 55
c 0
b 0
f 0
nc 104
nop 1
dl 0
loc 87
rs 6.5833

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php declare(strict_types=1);
2
3
namespace Shopware\Core\Content\MailTemplate\Subscriber;
4
5
use Psr\Log\LoggerInterface;
6
use Shopware\Core\Checkout\Document\DocumentService;
7
use Shopware\Core\Content\Mail\Service\AbstractMailService;
8
use Shopware\Core\Content\MailTemplate\Exception\MailEventConfigurationException;
9
use Shopware\Core\Content\MailTemplate\Exception\SalesChannelNotFoundException;
10
use Shopware\Core\Content\MailTemplate\MailTemplateActions;
11
use Shopware\Core\Content\MailTemplate\MailTemplateEntity;
12
use Shopware\Core\Content\MailTemplate\Service\MailServiceInterface;
13
use Shopware\Core\Content\Media\MediaService;
14
use Shopware\Core\Framework\Context;
15
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
16
use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
17
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
18
use Shopware\Core\Framework\Event\BusinessEvent;
19
use Shopware\Core\Framework\Event\EventData\EventDataType;
20
use Shopware\Core\Framework\Event\MailActionInterface;
21
use Shopware\Core\Framework\Feature;
22
use Shopware\Core\Framework\Validation\DataBag\DataBag;
23
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
24
25
class MailSendSubscriber implements EventSubscriberInterface
26
{
27
    public const ACTION_NAME = MailTemplateActions::MAIL_TEMPLATE_MAIL_SEND_ACTION;
28
    public const MAIL_CONFIG_EXTENSION = 'mail-attachments';
29
30
    /**
31
     * @var MailServiceInterface|null
32
     *
33
     * @deprecated tag:v6.4.0 (flag:FEATURE_NEXT_12246) property mailService will be removed
34
     */
35
    private $mailService;
36
37
    /**
38
     * @var EntityRepositoryInterface
39
     */
40
    private $mailTemplateRepository;
41
42
    /**
43
     * @var MediaService
44
     */
45
    private $mediaService;
46
47
    /**
48
     * @var EntityRepositoryInterface
49
     */
50
    private $mediaRepository;
51
52
    /**
53
     * @var DocumentService
54
     */
55
    private $documentService;
56
57
    /**
58
     * @var EntityRepositoryInterface
59
     */
60
    private $documentRepository;
61
62
    /**
63
     * @var LoggerInterface
64
     */
65
    private $logger;
66
67
    /**
68
     * @var AbstractMailService|null
69
     */
70
    private $emailService;
71
72
    public function __construct(
73
        ?MailServiceInterface $mailService,
74
        ?AbstractMailService $emailService,
75
        EntityRepositoryInterface $mailTemplateRepository,
76
        MediaService $mediaService,
77
        EntityRepositoryInterface $mediaRepository,
78
        EntityRepositoryInterface $documentRepository,
79
        DocumentService $documentService,
80
        LoggerInterface $logger
81
    ) {
82
        $this->mailService = $mailService;
0 ignored issues
show
Deprecated Code introduced by
The property Shopware\Core\Content\Ma...ubscriber::$mailService has been deprecated: tag:v6.4.0 (flag:FEATURE_NEXT_12246) property mailService will be removed ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

82
        /** @scrutinizer ignore-deprecated */ $this->mailService = $mailService;

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
83
        $this->mailTemplateRepository = $mailTemplateRepository;
84
        $this->mediaService = $mediaService;
85
        $this->mediaRepository = $mediaRepository;
86
        $this->documentRepository = $documentRepository;
87
        $this->documentService = $documentService;
88
        $this->logger = $logger;
89
        $this->emailService = $emailService;
90
    }
91
92
    public static function getSubscribedEvents(): array
93
    {
94
        return [
95
            self::ACTION_NAME => 'sendMail',
96
        ];
97
    }
98
99
    /**
100
     * @throws MailEventConfigurationException
101
     * @throws SalesChannelNotFoundException
102
     * @throws InconsistentCriteriaIdsException
103
     */
104
    public function sendMail(BusinessEvent $event): void
105
    {
106
        $mailEvent = $event->getEvent();
107
108
        $extension = $event->getContext()->getExtension(self::MAIL_CONFIG_EXTENSION);
109
        if (!$extension instanceof MailSendSubscriberConfig) {
110
            $extension = new MailSendSubscriberConfig(false, [], []);
111
        }
112
113
        if ($extension->skip()) {
114
            return;
115
        }
116
117
        if (!$mailEvent instanceof MailActionInterface) {
118
            throw new MailEventConfigurationException('Not a instance of MailActionInterface', \get_class($mailEvent));
119
        }
120
121
        $config = $event->getConfig();
122
123
        if (!isset($config['mail_template_id'])) {
124
            return;
125
        }
126
127
        $mailTemplate = $this->getMailTemplate($config['mail_template_id'], $event->getContext());
128
129
        if ($mailTemplate === null) {
130
            return;
131
        }
132
133
        $data = new DataBag();
134
135
        $recipients = $mailEvent->getMailStruct()->getRecipients();
136
        if (isset($config['recipients'])) {
137
            $recipients = $config['recipients'];
138
        }
139
140
        $data->set('recipients', $recipients);
141
        $data->set('senderName', $mailTemplate->getTranslation('senderName'));
142
        $data->set('salesChannelId', $mailEvent->getSalesChannelId());
143
144
        $data->set('templateId', $mailTemplate->getId());
145
        $data->set('customFields', $mailTemplate->getCustomFields());
146
        $data->set('contentHtml', $mailTemplate->getTranslation('contentHtml'));
147
        $data->set('contentPlain', $mailTemplate->getTranslation('contentPlain'));
148
        $data->set('subject', $mailTemplate->getTranslation('subject'));
149
        $data->set('mediaIds', []);
150
151
        $attachments = $this->buildAttachments($event, $mailTemplate, $extension);
152
153
        if (!empty($attachments)) {
154
            $data->set('binAttachments', $attachments);
155
        }
156
157
        try {
158
            //@deprecated tag:v6.4.0 (flag:FEATURE_NEXT_12246) remove complete if-else-branch
159
            // and only keep the if-content
160
            if (Feature::isActive('FEATURE_NEXT_12246') && $this->emailService !== null) {
161
                $this->emailService->send(
162
                    $data->all(),
163
                    $event->getContext(),
164
                    $this->getTemplateData($mailEvent)
165
                );
166
            } elseif ($this->mailService !== null) {
0 ignored issues
show
Deprecated Code introduced by
The property Shopware\Core\Content\Ma...ubscriber::$mailService has been deprecated: tag:v6.4.0 (flag:FEATURE_NEXT_12246) property mailService will be removed ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

166
            } elseif (/** @scrutinizer ignore-deprecated */ $this->mailService !== null) {

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
167
                $this->mailService->send(
0 ignored issues
show
Deprecated Code introduced by
The property Shopware\Core\Content\Ma...ubscriber::$mailService has been deprecated: tag:v6.4.0 (flag:FEATURE_NEXT_12246) property mailService will be removed ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

167
                /** @scrutinizer ignore-deprecated */ $this->mailService->send(

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
168
                    $data->all(),
169
                    $event->getContext(),
170
                    $this->getTemplateData($mailEvent)
171
                );
172
            } else {
173
                //@deprecated tag:v6.4.0 (flag:FEATURE_NEXT_12246) remove check for null and Exception on Feature Release
174
                throw new \Exception('Either `emailService` or `mailService` needs to be defined. Neither is.');
175
            }
176
177
            $writes = array_map(static function ($id) {
178
                return ['id' => $id, 'sent' => true];
179
            }, $extension->getDocumentIds());
180
181
            if (!empty($writes)) {
182
                $this->documentRepository->update($writes, $event->getContext());
183
            }
184
        } catch (\Exception $e) {
185
            $this->logger->error(
186
                "Could not send mail:\n"
187
                . $e->getMessage() . "\n"
188
                . 'Error Code:' . $e->getCode() . "\n"
189
                . "Template data: \n"
190
                . json_encode($data->all()) . "\n"
191
            );
192
        }
193
    }
194
195
    private function getMailTemplate(string $id, Context $context): ?MailTemplateEntity
196
    {
197
        $criteria = new Criteria([$id]);
198
        $criteria->addAssociation('media.media');
199
        $criteria->setLimit(1);
200
201
        return $this->mailTemplateRepository
202
            ->search($criteria, $context)
203
            ->first();
204
    }
205
206
    /**
207
     * @throws MailEventConfigurationException
208
     */
209
    private function getTemplateData(MailActionInterface $event): array
210
    {
211
        $data = [];
212
        /* @var EventDataType $item */
213
        foreach (array_keys($event::getAvailableData()->toArray()) as $key) {
214
            $getter = 'get' . ucfirst($key);
215
            if (method_exists($event, $getter)) {
216
                $data[$key] = $event->$getter();
217
            } else {
218
                throw new MailEventConfigurationException('Data for ' . $key . ' not available.', \get_class($event));
219
            }
220
        }
221
222
        return $data;
223
    }
224
225
    private function buildAttachments(BusinessEvent $event, MailTemplateEntity $mailTemplate, MailSendSubscriberConfig $config): array
226
    {
227
        $attachments = [];
228
229
        if ($mailTemplate->getMedia() !== null) {
230
            foreach ($mailTemplate->getMedia() as $mailTemplateMedia) {
231
                if ($mailTemplateMedia->getMedia() === null) {
232
                    continue;
233
                }
234
                if ($mailTemplateMedia->getLanguageId() !== null && $mailTemplateMedia->getLanguageId() !== $event->getContext()->getLanguageId()) {
235
                    continue;
236
                }
237
238
                $attachments[] = $this->mediaService->getAttachment(
239
                    $mailTemplateMedia->getMedia(),
240
                    $event->getContext()
241
                );
242
            }
243
        }
244
245
        if (!empty($config->getMediaIds())) {
246
            $entities = $this->mediaRepository->search(new Criteria($config->getMediaIds()), $event->getContext());
247
248
            foreach ($entities as $media) {
249
                $attachments[] = $this->mediaService->getAttachment($media, $event->getContext());
0 ignored issues
show
Bug introduced by
$media of type array is incompatible with the type Shopware\Core\Content\Media\MediaEntity expected by parameter $media of Shopware\Core\Content\Me...ervice::getAttachment(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

249
                $attachments[] = $this->mediaService->getAttachment(/** @scrutinizer ignore-type */ $media, $event->getContext());
Loading history...
250
            }
251
        }
252
253
        if (!empty($config->getDocumentIds())) {
254
            $criteria = new Criteria($config->getDocumentIds());
255
            $criteria->addAssociation('documentMediaFile');
256
            $criteria->addAssociation('documentType');
257
258
            $entities = $this->documentRepository->search($criteria, $event->getContext());
259
260
            foreach ($entities as $document) {
261
                $document = $this->documentService->getDocument($document, $event->getContext());
0 ignored issues
show
Bug introduced by
$document of type array is incompatible with the type Shopware\Core\Checkout\Document\DocumentEntity expected by parameter $document of Shopware\Core\Checkout\D...tService::getDocument(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

261
                $document = $this->documentService->getDocument(/** @scrutinizer ignore-type */ $document, $event->getContext());
Loading history...
262
263
                $attachments[] = [
264
                    'content' => $document->getFileBlob(),
265
                    'fileName' => $document->getFilename(),
266
                    'mimeType' => $document->getContentType(),
267
                ];
268
            }
269
        }
270
271
        return $attachments;
272
    }
273
}
274