Skip to content

Commit

Permalink
Merge pull request #7 from CPS-IT/feature/flush-queue
Browse files Browse the repository at this point in the history
[FEATURE] Introduce `mailqueue:flushqueue` console command
  • Loading branch information
eliashaeussler authored Mar 5, 2024
2 parents aecdb5c + 10d7256 commit f952faf
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 10 deletions.
192 changes: 192 additions & 0 deletions Classes/Command/FlushQueueCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
<?php

declare(strict_types=1);

/*
* This file is part of the TYPO3 CMS extension "mailqueue".
*
* Copyright (C) 2024 Elias Häußler <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

namespace CPSIT\Typo3Mailqueue\Command;

use CPSIT\Typo3Mailqueue\Mail;
use Symfony\Component\Console;
use TYPO3\CMS\Core;

/**
* FlushQueueCommand
*
* @author Elias Häußler <[email protected]>
* @license GPL-2.0-or-later
*/
final class FlushQueueCommand extends Console\Command\Command
{
private ?Console\Output\OutputInterface $jsonOutput = null;
private Console\Style\SymfonyStyle $io;

public function __construct(
private readonly Core\Mail\Mailer $mailer,
) {
parent::__construct();
}

protected function configure(): void
{
$this->addOption(
'json',
'j',
Console\Input\InputOption::VALUE_NONE,
'Output results in JSON format',
);
$this->addOption(
'limit',
'l',
Console\Input\InputOption::VALUE_REQUIRED,
'Maximum number of mails to send in one iteration',
);
}

protected function initialize(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): void
{
if ($input->getOption('json')) {
$this->jsonOutput = $output;

if ($output instanceof Console\Output\ConsoleOutputInterface) {
$output = $output->getErrorOutput();
} else {
$output = new Console\Output\NullOutput();
}
}

$this->io = new Console\Style\SymfonyStyle($input, $output);
}

protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): int
{
$limit = $input->getOption('limit');
$transport = $this->mailer->getTransport();

// Early return if unsupported mail transport is configured
if (!($transport instanceof Mail\Transport\QueueableTransport)) {
$message = sprintf(
'The configured mail transport "%s" is not supported. Please configure a mail spooler as mail transport.',
$transport::class,
);

$this->io->error($message);
$this->writeJsonResult([
'error' => $message,
]);

return self::INVALID;
}

$mailQueue = $transport->getMailQueue();
$numberOfMailsInQueue = count($mailQueue);
$realTransport = $this->mailer->getRealTransport();

// Early return if mail queue is empty
if ($numberOfMailsInQueue === 0) {
$message = 'No mails are currently in queue.';

$this->io->success($message);
$this->writeJsonResult([
'result' => $message,
]);

return self::SUCCESS;
}

// Limit number of sent mails from command option or send all mails
if ($limit !== null) {
$limit = (int)$limit;
} else {
$limit = $numberOfMailsInQueue;
}

// Early return if invalid limit is provided
if ($limit < 1) {
$message = 'Limit must be a number greater than or equal to 1.';

$this->io->error($message);
$this->writeJsonResult([
'error' => $message,
]);

return self::INVALID;
}

$this->io->section('Flushing mail queue');

$progressBar = $this->io->createProgressBar($limit);

// Send mails from queue
foreach ($progressBar->iterate($mailQueue, $limit) as $i => $item) {
if ($i >= $limit) {
$progressBar->finish();
break;
}

$transport->dequeue($item, $realTransport);

--$numberOfMailsInQueue;
}

$this->io->newLine(2);

if ($numberOfMailsInQueue > 0) {
$this->io->success(
sprintf(
'Successfully sent %d mail%s, %d mail%s still enqueued.',
$limit,
$limit === 1 ? '' : 's',
$numberOfMailsInQueue,
$numberOfMailsInQueue === 1 ? ' is' : 's are',
),
);
} else {
$this->io->success(
sprintf(
'Successfully flushed mail queue (sent %d mail%s).',
$limit,
$limit === 1 ? '' : 's',
),
);
}

$this->writeJsonResult([
'sent' => $limit,
'remaining' => $numberOfMailsInQueue,
]);

return self::SUCCESS;
}

/**
* @param array<string, mixed> $json
*/
private function writeJsonResult(array $json): void
{
if ($this->jsonOutput === null) {
return;
}

$this->jsonOutput->writeln(
json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR),
);
}
}
7 changes: 7 additions & 0 deletions Configuration/Services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ services:
# @todo Replace with #[AsController] attribute once support for TYPO3 v11 is dropped
tags: ['backend.controller']

CPSIT\Typo3Mailqueue\Command\FlushQueueCommand:
# @todo Replace with #[AsCommand] attribute once support for TYPO3 v11 is dropped
tags:
- name: console.command
command: 'mailqueue:flushqueue'
description: 'Flush mail queue by sending mails using the configured real transport'

CPSIT\Typo3Mailqueue\Command\ListQueueCommand:
# @todo Replace with #[AsCommand] attribute once support for TYPO3 v11 is dropped
tags:
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 22 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ An extension for TYPO3 CMS that extends TYPO3's mail spooling functionality
with an extended queueable mail transport interface. In addition, it provides
an improved version of TYPO3's `FileSpooler`. In order to make mails in the
mail queue visible, the extension provides an (admin-only) backend module and
a console command.
console commands to list and flush the mail queue.

## 🚀 Features

* Extended interface for queueable mail transports
* Improved queueable file transport with failure metadata
* Backend module to list mails in queue
* Console command to list mails in queue
* Console command to list queue and flush mails
* Compatible with TYPO3 11.5 LTS and 12.4 LTS

## 🔥 Installation
Expand Down Expand Up @@ -98,9 +98,27 @@ be used to get a quick overview about the health state of the mail queue.
It also allows to dequeue single mails from the mail queue by sending them
with the configured real transport.

### Console command
### Console commands

![Screenshot console command](Documentation/Images/ScreenshotConsoleCommand.png)
#### Flush queue

![Screenshot "mailqueue:flushqueue" console command](Documentation/Images/ScreenshotFlushQueueCommand.png)

The extension provides a console command to flush the mail queue:

```bash
typo3 mailqueue:flushqueue [-l|--limit] [-j|--json]
```

The number of mails to be sent can be limited with `--limit` (or `-l`). If
no limit is passed, the whole mail queue is flushed.

When using `--json` (or `-j`), user-oriented output is written to stderr and
result messages are written in JSON format to stdout.

#### List queue

![Screenshot "mailqueue:listqueue" console command](Documentation/Images/ScreenshotListQueueCommand.png)

The extension provides a console command to list enqueued mails:

Expand Down
16 changes: 10 additions & 6 deletions Tests/Build/console-application.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,18 @@

require dirname(__DIR__, 2) . '/.Build/vendor/autoload.php';

$command = new Command\ListQueueCommand(
new Core\Mail\Mailer(
new Mailer\Transport\NullTransport(),
),
$mailer = new Core\Mail\Mailer(
new Mailer\Transport\NullTransport(),
);
$command->setName('mailqueue:listqueue');

$flushCommand = new Command\FlushQueueCommand($mailer);
$flushCommand->setName('mailqueue:flushqueue');

$listCommand = new Command\ListQueueCommand($mailer);
$listCommand->setName('mailqueue:listqueue');

$application = new Console\Application();
$application->add($command);
$application->add($flushCommand);
$application->add($listCommand);

return $application;

0 comments on commit f952faf

Please sign in to comment.