• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CPS-IT / mailqueue / 27526284931

15 Jun 2026 05:36AM UTC coverage: 16.616%. Remained the same
27526284931

push

github

web-flow
Merge pull request #298 from CPS-IT/taks/drop-typo3-v12

[!!!][TASK] Drop support for TYPO3 v12

0 of 1 new or added line in 1 file covered. (0.0%)

110 of 662 relevant lines covered (16.62%)

0.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/Classes/Controller/MailqueueModuleController.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the TYPO3 CMS extension "mailqueue".
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
17

18
namespace CPSIT\Typo3Mailqueue\Controller;
19

20
use CPSIT\Typo3Mailqueue\Configuration;
21
use CPSIT\Typo3Mailqueue\Enums;
22
use CPSIT\Typo3Mailqueue\Exception;
23
use CPSIT\Typo3Mailqueue\Mail;
24
use CPSIT\Typo3Mailqueue\Traits;
25
use Psr\Http\Message;
26
use Symfony\Component\Mailer;
27
use TYPO3\CMS\Backend;
28
use TYPO3\CMS\Core;
29
use TYPO3\CMS\Core\Imaging\IconSize;
30

31
/**
32
 * MailqueueModuleController
33
 *
34
 * @author Elias Häußler <e.haeussler@familie-redlich.de>
35
 * @license GPL-2.0-or-later
36
 */
37
#[Backend\Attribute\AsController]
38
final class MailqueueModuleController
39
{
40
    use Traits\TranslatableTrait;
41
    use Core\Http\AllowedMethodsTrait;
42

43
    public function __construct(
×
44
        private readonly Configuration\ExtensionConfiguration $extensionConfiguration,
45
        private readonly Core\Imaging\IconFactory $iconFactory,
46
        private readonly Backend\Template\ModuleTemplateFactory $moduleTemplateFactory,
47
        private readonly Core\Mail\Mailer $mailer,
48
        private readonly Backend\Routing\UriBuilder $uriBuilder,
49
        private readonly Core\Context\Context $context,
50
    ) {}
×
51

52
    public function __invoke(Message\ServerRequestInterface $request): Message\ResponseInterface
×
53
    {
54
        $page = $this->resolvePageIdFromRequest($request);
×
55

56
        // Force redirect when page selector was used
57
        if ($request->getMethod() === 'POST' && !isset($request->getQueryParams()['page'])) {
×
58
            return new Core\Http\RedirectResponse(
×
59
                $this->uriBuilder->buildUriFromRoute('system_mailqueue', ['page' => $page]),
×
60
            );
×
61
        }
62

63
        $this->assertAllowedHttpMethod($request, 'GET');
×
64

65
        $template = $this->moduleTemplateFactory->create($request);
×
66
        $transport = $this->mailer->getTransport();
×
67
        /** @var string|null $sendId */
68
        $sendId = $request->getQueryParams()['send'] ?? null;
×
69
        /** @var string|null $deleteId */
70
        $deleteId = $request->getQueryParams()['delete'] ?? null;
×
71

72
        if ($transport instanceof Mail\Transport\QueueableTransport) {
×
73
            $templateVariables = $this->resolveTemplateVariables($transport, $page, $sendId, $deleteId);
×
74
        } else {
75
            $templateVariables = [
×
76
                'unsupportedTransport' => $this->getTransportFromMailConfiguration(),
×
77
            ];
×
78
        }
79

80
        if (Core\Utility\ExtensionManagementUtility::isLoaded('lowlevel')) {
×
81
            $this->addLinkToConfigurationModule($template);
×
82
        }
83

84
        return $template
×
85
            ->assignMultiple($templateVariables)
×
86
            ->renderResponse('List')
×
87
        ;
×
88
    }
89

90
    private function resolvePageIdFromRequest(Message\ServerRequestInterface $request): int
×
91
    {
92
        $pageId = $request->getQueryParams()['page'] ?? null;
×
93

94
        if (\is_numeric($pageId)) {
×
95
            return (int)$pageId;
×
96
        }
97

98
        if (!\is_array($request->getParsedBody())) {
×
99
            return 1;
×
100
        }
101

102
        $pageId = $request->getParsedBody()['page'] ?? 1;
×
103

104
        if (\is_numeric($pageId)) {
×
105
            return (int)$pageId;
×
106
        }
107

108
        return 1;
×
109
    }
110

111
    /**
112
     * @return array{
113
     *     delayThreshold: positive-int,
114
     *     deleteResult: bool,
115
     *     failing: bool,
116
     *     longestPendingInterval: non-negative-int,
117
     *     pagination: Core\Pagination\SimplePagination,
118
     *     paginator: Core\Pagination\ArrayPaginator,
119
     *     queue: list<Mail\Queue\MailQueueItem>,
120
     *     sendResult: Enums\MailState|null,
121
     * }
122
     */
123
    private function resolveTemplateVariables(
×
124
        Mail\Transport\QueueableTransport $transport,
125
        int $currentPageNumber = 1,
126
        ?string $sendId = null,
127
        ?string $deleteId = null,
128
    ): array {
129
        $failing = false;
×
130
        $longestPendingInterval = 0;
×
131
        /** @var int $now */
132
        $now = $this->context->getPropertyFromAspect('date', 'timestamp');
×
133
        $sendResult = null;
×
134
        $deleteResult = false;
×
135

136
        if (is_string($sendId)) {
×
137
            $sendResult = $this->sendMail($transport, $sendId);
×
138
        }
139

140
        if (is_string($deleteId)) {
×
141
            $deleteResult = $this->deleteMail($transport, $deleteId);
×
142
        }
143

144
        foreach ($transport->getMailQueue() as $mailQueueItem) {
×
145
            if ($mailQueueItem->date !== null) {
×
146
                $longestPendingInterval = max($longestPendingInterval, $now - $mailQueueItem->date->getTimestamp());
×
147
            }
148

149
            if ($mailQueueItem->state === Enums\MailState::Failed) {
×
150
                $failing = true;
×
151
            }
152
        }
153

154
        $queue = $transport->getMailQueue()->get();
×
155
        $paginator = new Core\Pagination\ArrayPaginator(
×
156
            $queue,
×
157
            $currentPageNumber,
×
158
            $this->extensionConfiguration->itemsPerPage,
×
159
        );
×
160
        $pagination = new Core\Pagination\SimplePagination($paginator);
×
161

162
        return [
×
163
            'delayThreshold' => $this->extensionConfiguration->queueDelayThreshold,
×
164
            'deleteResult' => $deleteResult,
×
165
            'failing' => $failing,
×
166
            'longestPendingInterval' => $longestPendingInterval,
×
167
            'pagination' => $pagination,
×
168
            'paginator' => $paginator,
×
169
            'queue' => $queue,
×
170
            'sendResult' => $sendResult,
×
171
        ];
×
172
    }
173

174
    private function sendMail(Mail\Transport\QueueableTransport $transport, string $queueItemId): Enums\MailState
×
175
    {
176
        $mailQueueItem = $this->getMailById($transport, $queueItemId);
×
177

178
        if ($mailQueueItem === null) {
×
179
            return Enums\MailState::AlreadySent;
×
180
        }
181

182
        try {
183
            $transport->dequeue($mailQueueItem, $this->mailer->getRealTransport());
×
184
        } catch (Mailer\Exception\TransportExceptionInterface) {
×
185
            return Enums\MailState::Failed;
×
186
        }
187

188
        return Enums\MailState::Sent;
×
189
    }
190

191
    private function deleteMail(Mail\Transport\QueueableTransport $transport, string $queueItemId): bool
×
192
    {
193
        $mailQueueItem = $this->getMailById($transport, $queueItemId);
×
194

195
        if ($mailQueueItem === null) {
×
196
            return false;
×
197
        }
198

199
        return $transport->delete($mailQueueItem);
×
200
    }
201

202
    private function getMailById(
×
203
        Mail\Transport\QueueableTransport $transport,
204
        string $queueItemId,
205
    ): ?Mail\Queue\MailQueueItem {
206
        foreach ($transport->getMailQueue() as $mailQueueItem) {
×
207
            if ($mailQueueItem->id === $queueItemId) {
×
208
                return $mailQueueItem;
×
209
            }
210
        }
211

212
        return null;
×
213
    }
214

215
    private function addLinkToConfigurationModule(Backend\Template\ModuleTemplate $template): void
×
216
    {
217
        $buttonBar = $template->getDocHeaderComponent()->getButtonBar();
×
218

219
        $button = $buttonBar->makeLinkButton();
×
220
        $button->setHref(
×
221
            (string)$this->uriBuilder->buildUriFromRoute(
×
222
                'system_config',
×
223
                ['node' => ['MAIL' => 1], 'tree' => 'confVars'],
×
224
            )
×
225
        );
×
NEW
226
        $button->setIcon($this->iconFactory->getIcon('actions-cog', IconSize::SMALL));
×
227
        $button->setTitle(self::translate('button.config'));
×
228
        $button->setShowLabelText(true);
×
229

230
        $buttonBar->addButton($button);
×
231
    }
232

233
    /**
234
     * @throws Exception\MailTransportIsNotConfigured
235
     */
236
    private function getTransportFromMailConfiguration(): string
×
237
    {
238
        $mailConfiguration = $GLOBALS['TYPO3_CONF_VARS']['MAIL'] ?? null;
×
239

240
        if (!\is_array($mailConfiguration)) {
×
241
            throw new Exception\MailTransportIsNotConfigured();
×
242
        }
243

244
        $spoolType = $mailConfiguration['transport_spool_type'] ?? null;
×
245

246
        if (is_string($spoolType) && trim($spoolType) !== '') {
×
247
            return $spoolType;
×
248
        }
249

250
        $transport = $mailConfiguration['transport'] ?? null;
×
251

252
        if (is_string($transport) && trim($transport) !== '') {
×
253
            return $transport;
×
254
        }
255

256
        throw new Exception\MailTransportIsNotConfigured();
×
257
    }
258
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc