Passed
Push — trunk ( 9f8579...29fffa )
by Christian
13:21 queued 11s
created

SendMailAction::buildAttachments()   C

Complexity

Conditions 12
Paths 16

Size

Total Lines 51
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 24
nc 16
nop 5
dl 0
loc 51
rs 6.9666
c 0
b 0
f 0

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\Flow\Dispatching\Action;
4
5
use Doctrine\DBAL\Connection;
6
use Psr\Log\LoggerInterface;
7
use Shopware\Core\Content\Flow\Dispatching\DelayableAction;
8
use Shopware\Core\Content\Flow\Dispatching\StorableFlow;
9
use Shopware\Core\Content\Flow\Events\FlowSendMailActionEvent;
10
use Shopware\Core\Content\Mail\Service\AbstractMailService;
11
use Shopware\Core\Content\Mail\Service\MailAttachmentsConfig;
12
use Shopware\Core\Content\MailTemplate\Exception\MailEventConfigurationException;
13
use Shopware\Core\Content\MailTemplate\Exception\SalesChannelNotFoundException;
14
use Shopware\Core\Content\MailTemplate\MailTemplateActions;
15
use Shopware\Core\Content\MailTemplate\MailTemplateEntity;
0 ignored issues
show
Bug introduced by
The type Shopware\Core\Content\Ma...late\MailTemplateEntity was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use Shopware\Core\Content\MailTemplate\Subscriber\MailSendSubscriberConfig;
17
use Shopware\Core\Framework\Adapter\Translation\Translator;
18
use Shopware\Core\Framework\Context;
19
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
20
use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
21
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
22
use Shopware\Core\Framework\Event\MailAware;
23
use Shopware\Core\Framework\Event\OrderAware;
24
use Shopware\Core\Framework\Uuid\Uuid;
25
use Shopware\Core\Framework\Validation\DataBag\DataBag;
26
use Shopware\Core\System\Locale\LanguageLocaleCodeProvider;
27
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
28
29
/**
30
 * @package business-ops
31
 *
32
 * @internal
33
 */
34
class SendMailAction extends FlowAction implements DelayableAction
35
{
36
    public const ACTION_NAME = MailTemplateActions::MAIL_TEMPLATE_MAIL_SEND_ACTION;
37
    public const MAIL_CONFIG_EXTENSION = 'mail-attachments';
38
    private const RECIPIENT_CONFIG_ADMIN = 'admin';
39
    private const RECIPIENT_CONFIG_CUSTOM = 'custom';
40
    private const RECIPIENT_CONFIG_CONTACT_FORM_MAIL = 'contactFormMail';
41
42
    private EntityRepository $mailTemplateRepository;
43
44
    private LoggerInterface $logger;
45
46
    private AbstractMailService $emailService;
47
48
    private EventDispatcherInterface $eventDispatcher;
49
50
    private EntityRepository $mailTemplateTypeRepository;
51
52
    private Translator $translator;
53
54
    private Connection $connection;
55
56
    private LanguageLocaleCodeProvider $languageLocaleProvider;
57
58
    private bool $updateMailTemplate;
59
60
    /**
61
     * @internal
62
     */
63
    public function __construct(
64
        AbstractMailService $emailService,
65
        EntityRepository $mailTemplateRepository,
66
        LoggerInterface $logger,
67
        EventDispatcherInterface $eventDispatcher,
68
        EntityRepository $mailTemplateTypeRepository,
69
        Translator $translator,
70
        Connection $connection,
71
        LanguageLocaleCodeProvider $languageLocaleProvider,
72
        bool $updateMailTemplate
73
    ) {
74
        $this->mailTemplateRepository = $mailTemplateRepository;
75
        $this->logger = $logger;
76
        $this->emailService = $emailService;
77
        $this->eventDispatcher = $eventDispatcher;
78
        $this->mailTemplateTypeRepository = $mailTemplateTypeRepository;
79
        $this->translator = $translator;
80
        $this->connection = $connection;
81
        $this->languageLocaleProvider = $languageLocaleProvider;
82
        $this->updateMailTemplate = $updateMailTemplate;
83
    }
84
85
    public static function getName(): string
86
    {
87
        return 'action.mail.send';
88
    }
89
90
    /**
91
     * @return array<string>
92
     */
93
    public function requirements(): array
94
    {
95
        return [MailAware::class];
96
    }
97
98
    /**
99
     * @throws MailEventConfigurationException
100
     * @throws SalesChannelNotFoundException
101
     * @throws InconsistentCriteriaIdsException
102
     */
103
    public function handleFlow(StorableFlow $flow): void
104
    {
105
        $extension = $flow->getContext()->getExtension(self::MAIL_CONFIG_EXTENSION);
106
        if (!$extension instanceof MailSendSubscriberConfig) {
107
            $extension = new MailSendSubscriberConfig(false, [], []);
108
        }
109
110
        if ($extension->skip()) {
111
            return;
112
        }
113
114
        if (!$flow->hasStore(MailAware::MAIL_STRUCT) || !$flow->hasStore(MailAware::SALES_CHANNEL_ID)) {
115
            throw new MailEventConfigurationException('Not have data from MailAware', \get_class($flow));
116
        }
117
118
        $eventConfig = $flow->getConfig();
119
        if (empty($eventConfig['recipient'])) {
120
            throw new MailEventConfigurationException('The recipient value in the flow action configuration is missing.', \get_class($flow));
121
        }
122
123
        if (!isset($eventConfig['mailTemplateId'])) {
124
            return;
125
        }
126
127
        $mailTemplate = $this->getMailTemplate($eventConfig['mailTemplateId'], $flow->getContext());
128
129
        if ($mailTemplate === null) {
130
            return;
131
        }
132
133
        $injectedTranslator = $this->injectTranslator($flow->getContext(), $flow->getStore(MailAware::SALES_CHANNEL_ID));
134
135
        $data = new DataBag();
136
137
        $recipients = $this->getRecipients(
138
            $eventConfig['recipient'],
139
            $flow->getStore(MailAware::MAIL_STRUCT)['recipients'],
140
            $flow->getStore('contactFormData', []),
141
        );
142
143
        if (empty($recipients)) {
144
            return;
145
        }
146
147
        $data->set('recipients', $recipients);
148
        $data->set('senderName', $mailTemplate->getTranslation('senderName'));
149
        $data->set('salesChannelId', $flow->getStore(MailAware::SALES_CHANNEL_ID));
150
151
        $data->set('templateId', $mailTemplate->getId());
152
        $data->set('customFields', $mailTemplate->getCustomFields());
153
        $data->set('contentHtml', $mailTemplate->getTranslation('contentHtml'));
154
        $data->set('contentPlain', $mailTemplate->getTranslation('contentPlain'));
155
        $data->set('subject', $mailTemplate->getTranslation('subject'));
156
        $data->set('mediaIds', []);
157
158
        $data->set('attachmentsConfig', new MailAttachmentsConfig(
159
            $flow->getContext(),
160
            $mailTemplate,
161
            $extension,
162
            $eventConfig,
163
            $flow->getStore(OrderAware::ORDER_ID),
164
        ));
165
166
        if (!empty($eventConfig['replyTo'])) {
167
            $data->set('senderMail', $eventConfig['replyTo']);
168
        }
169
170
        $this->eventDispatcher->dispatch(new FlowSendMailActionEvent($data, $mailTemplate, $flow));
171
172
        if ($data->has('templateId')) {
173
            $this->updateMailTemplateType(
174
                $flow->getContext(),
175
                $flow,
176
                $flow->data(),
177
                $mailTemplate
178
            );
179
        }
180
181
        $this->send($data, $flow->getContext(), $flow->data(), $extension, $injectedTranslator);
182
    }
183
184
    /**
185
     * @param array<string, mixed> $templateData
186
     */
187
    private function send(DataBag $data, Context $context, array $templateData, MailSendSubscriberConfig $extension, bool $injectedTranslator): void
188
    {
189
        try {
190
            $this->emailService->send(
191
                $data->all(),
192
                $context,
193
                $templateData
194
            );
195
        } catch (\Exception $e) {
196
            $this->logger->error(
197
                "Could not send mail:\n"
198
                . $e->getMessage() . "\n"
199
                . 'Error Code:' . $e->getCode() . "\n"
200
                . "Template data: \n"
201
                . json_encode($data->all()) . "\n"
202
            );
203
        }
204
205
        if ($injectedTranslator) {
206
            $this->translator->resetInjection();
207
        }
208
    }
209
210
    /**
211
     * @param array<string, mixed> $templateData
212
     */
213
    private function updateMailTemplateType(
214
        Context $context,
215
        StorableFlow $event,
216
        array $templateData,
217
        MailTemplateEntity $mailTemplate
218
    ): void {
219
        if (!$mailTemplate->getMailTemplateTypeId()) {
220
            return;
221
        }
222
223
        if (!$this->updateMailTemplate) {
224
            return;
225
        }
226
227
        $mailTemplateTypeTranslation = $this->connection->fetchOne(
228
            'SELECT 1 FROM mail_template_type_translation WHERE language_id = :languageId AND mail_template_type_id =:mailTemplateTypeId',
229
            [
230
                'languageId' => Uuid::fromHexToBytes($context->getLanguageId()),
231
                'mailTemplateTypeId' => Uuid::fromHexToBytes($mailTemplate->getMailTemplateTypeId()),
232
            ]
233
        );
234
235
        if (!$mailTemplateTypeTranslation) {
236
            // Don't throw errors if this fails // Fix with NEXT-15475
237
            $this->logger->error(
238
                "Could not update mail template type, because translation for this language does not exits:\n"
239
                . 'Flow id: ' . $event->getFlowState()->flowId . "\n"
240
                . 'Sequence id: ' . $event->getFlowState()->getSequenceId()
241
            );
242
243
            return;
244
        }
245
246
        $this->mailTemplateTypeRepository->update([[
247
            'id' => $mailTemplate->getMailTemplateTypeId(),
248
            'templateData' => $templateData,
249
        ]], $context);
250
    }
251
252
    private function getMailTemplate(string $id, Context $context): ?MailTemplateEntity
253
    {
254
        $criteria = new Criteria([$id]);
255
        $criteria->setTitle('send-mail::load-mail-template');
256
        $criteria->addAssociation('media.media');
257
        $criteria->setLimit(1);
258
259
        return $this->mailTemplateRepository
260
            ->search($criteria, $context)
261
            ->first();
262
    }
263
264
    private function injectTranslator(Context $context, ?string $salesChannelId): bool
265
    {
266
        if ($salesChannelId === null) {
267
            return false;
268
        }
269
270
        if ($this->translator->getSnippetSetId() !== null) {
271
            return false;
272
        }
273
274
        $this->translator->injectSettings(
275
            $salesChannelId,
276
            $context->getLanguageId(),
277
            $this->languageLocaleProvider->getLocaleForLanguageId($context->getLanguageId()),
278
            $context
279
        );
280
281
        return true;
282
    }
283
284
    /**
285
     * @param array<string, mixed> $recipients
286
     * @param array<string, mixed> $mailStructRecipients
287
     * @param array<int|string, mixed> $contactFormData
288
     *
289
     * @return array<int|string, string>
290
     */
291
    private function getRecipients(array $recipients, array $mailStructRecipients, array $contactFormData): array
292
    {
293
        switch ($recipients['type']) {
294
            case self::RECIPIENT_CONFIG_CUSTOM:
295
                return $recipients['data'];
296
            case self::RECIPIENT_CONFIG_ADMIN:
297
                $admins = $this->connection->fetchAllAssociative(
298
                    'SELECT first_name, last_name, email FROM user WHERE admin = true'
299
                );
300
                $emails = [];
301
                foreach ($admins as $admin) {
302
                    $emails[$admin['email']] = $admin['first_name'] . ' ' . $admin['last_name'];
303
                }
304
305
                return $emails;
306
            case self::RECIPIENT_CONFIG_CONTACT_FORM_MAIL:
307
                if (empty($contactFormData)) {
308
                    return [];
309
                }
310
311
                if (!\array_key_exists('email', $contactFormData)) {
312
                    return [];
313
                }
314
315
                return [$contactFormData['email'] => ($contactFormData['firstName'] ?? '') . ' ' . ($contactFormData['lastName'] ?? '')];
316
            default:
317
                return $mailStructRecipients;
318
        }
319
    }
320
}
321