Skip to content

Commit

Permalink
Merge pull request #14 from CPS-IT/feature/pagination
Browse files Browse the repository at this point in the history
[FEATURE] Add pagination to backend module
  • Loading branch information
eliashaeussler authored Mar 7, 2024
2 parents d910166 + 74a6a75 commit 21036c2
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 6 deletions.
57 changes: 57 additions & 0 deletions Classes/Configuration/ExtensionConfiguration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

/*
* This file is part of the TYPO3 CMS extension "mailqueue".
*
* Copyright (C) 2024 Elias Häußler <elias@haeussler.dev>
*
* 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\Configuration;

use CPSIT\Typo3Mailqueue\Extension;
use TYPO3\CMS\Core;

/**
* ExtensionConfiguration
*
* @author Elias Häußler <e.haeussler@familie-redlich.de>
* @license GPL-2.0-or-later
*/
final class ExtensionConfiguration
{
private const DEFAULT_ITEMS_PER_PAGE = 20;

public function __construct(
private readonly Core\Configuration\ExtensionConfiguration $configuration,
) {}

public function getItemsPerPage(): int
{
try {
$itemsPerPage = $this->configuration->get(Extension::KEY, 'pagination/itemsPerPage');
} catch (Core\Exception) {
return self::DEFAULT_ITEMS_PER_PAGE;
}

if (!is_scalar($itemsPerPage)) {
return self::DEFAULT_ITEMS_PER_PAGE;
}

return max(1, (int)$itemsPerPage);
}
}
29 changes: 26 additions & 3 deletions Classes/Controller/MailqueueModuleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

namespace CPSIT\Typo3Mailqueue\Controller;

use CPSIT\Typo3Mailqueue\Configuration;
use CPSIT\Typo3Mailqueue\Enums;
use CPSIT\Typo3Mailqueue\Exception;
use CPSIT\Typo3Mailqueue\Mail;
Expand All @@ -46,6 +47,7 @@ final class MailqueueModuleController
private readonly Core\Information\Typo3Version $typo3Version;

public function __construct(
private readonly Configuration\ExtensionConfiguration $extensionConfiguration,
private readonly Core\Imaging\IconFactory $iconFactory,
private readonly Backend\Template\ModuleTemplateFactory $moduleTemplateFactory,
private readonly Core\Mail\Mailer $mailer,
Expand All @@ -58,10 +60,18 @@ public function __invoke(Message\ServerRequestInterface $request): Message\Respo
{
$template = $this->moduleTemplateFactory->create($request);
$transport = $this->mailer->getTransport();
$page = (int)($request->getQueryParams()['page'] ?? $request->getParsedBody()['page'] ?? 1);
$sendId = $request->getQueryParams()['send'] ?? null;

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

if ($transport instanceof Mail\Transport\QueueableTransport) {
$templateVariables = $this->resolveTemplateVariables($transport, $sendId);
$templateVariables = $this->resolveTemplateVariables($transport, $page, $sendId);
} else {
$templateVariables = [
'unsupportedTransport' => $this->getTransportFromMailConfiguration(),
Expand Down Expand Up @@ -91,12 +101,15 @@ public function __invoke(Message\ServerRequestInterface $request): Message\Respo
* @return array{
* failing: bool,
* longestPendingInterval: non-negative-int,
* pagination: Core\Pagination\SimplePagination,
* paginator: Core\Pagination\ArrayPaginator,
* queue: list<Mail\Queue\MailQueueItem>,
* sendResult: Enums\MailState|null,
* transport: Mail\Transport\QueueableTransport,
* }
*/
private function resolveTemplateVariables(
Mail\Transport\QueueableTransport $transport,
int $currentPageNumber = 1,
string $sendId = null,
): array {
$failing = false;
Expand All @@ -118,11 +131,21 @@ private function resolveTemplateVariables(
}
}

$queue = $transport->getMailQueue()->get();
$paginator = new Core\Pagination\ArrayPaginator(
$queue,
$currentPageNumber,
$this->extensionConfiguration->getItemsPerPage(),
);
$pagination = new Core\Pagination\SimplePagination($paginator);

return [
'failing' => $failing,
'longestPendingInterval' => $longestPendingInterval,
'pagination' => $pagination,
'paginator' => $paginator,
'queue' => $queue,
'sendResult' => $sendResult,
'transport' => $transport,
];
}

Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Alternatively, you can download the extension via the
## ⚡ Usage

> [!NOTE]
> In order to use a queueable mail transport, you need to [configure](#-configuration)
> In order to use a queueable mail transport, you need to [configure](#mail-settings)
> it in your system settings, along with the required transport settings.
### Concept
Expand Down Expand Up @@ -160,6 +160,8 @@ native mail spoolers:

## 📂 Configuration

### Mail settings

Queueable mail transports are registered the "normal" way as described in the
[official TYPO3 core documentation][3]. Add the following to your system configuration
(e.g. in `additional.php`/`AdditionalConfiguration.php`):
Expand All @@ -177,6 +179,14 @@ $GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_spool_type'] = 'memory';
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_spool_type'] = \Vendor\Extension\Mail\Transport\CustomQueueableTransport::class;
```

### Extension configuration

The following extension configuration options are available:

| Configuration key | Description | Required | Default |
|-------------------------------|----------------------------------------------------------------|----------|---------|
| **`pagination.itemsPerPage`** | Number of mails to display on a single page in backend module || `20` |

## 🧑‍💻 Contributing

Please have a look at [`CONTRIBUTING.md`](CONTRIBUTING.md).
Expand Down
28 changes: 28 additions & 0 deletions Resources/Private/Language/locallang.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,21 @@
<trans-unit id="aria.close">
<source>Close</source>
</trans-unit>
<trans-unit id="aria.first">
<source>First</source>
</trans-unit>
<trans-unit id="aria.previous">
<source>Previous</source>
</trans-unit>
<trans-unit id="aria.last">
<source>Last</source>
</trans-unit>
<trans-unit id="aria.next">
<source>Next</source>
</trans-unit>
<trans-unit id="aria.reload">
<source>Reload</source>
</trans-unit>

<trans-unit id="button.info">
<source>View info</source>
Expand All @@ -135,6 +150,19 @@
<trans-unit id="button.config">
<source>View mail configuration</source>
</trans-unit>

<trans-unit id="pagination.paginatedItems">
<source>Mails %d - %d</source>
</trans-unit>
<trans-unit id="pagination.pageRange">
<source>Page %d of %d</source>
</trans-unit>
<trans-unit id="pagination.pageRange.start">
<source>Page</source>
</trans-unit>
<trans-unit id="pagination.pageRange.end">
<source>of %d</source>
</trans-unit>
</body>
</file>
</xliff>
117 changes: 117 additions & 0 deletions Resources/Private/Partials/List/Pagination.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
xmlns:c="http://typo3.org/ns/TYPO3/CMS/Core/ViewHelpers"
data-namespace-typo3-fluid="true">

<f:if condition="{paginator.numberOfPages} > 1">
<tr>
<td colspan="6">
<nav class="mb-2 mt-2">
<span class="page-item ps-2 pe-2">
<f:translate key="pagination.paginatedItems" extensionName="Mailqueue" arguments="{
0: '{paginator.keyOfFirstPaginatedItem + 1}',
1: '{paginator.keyOfLastPaginatedItem + 1}'
}" />
<span class="visually-hidden">,
<f:translate key="pagination.pageRange" extensionName="Mailqueue" arguments="{
0: paginator.currentPageNumber,
1: pagination.lastPageNumber
}" />
</span>
</span>

<ul class="pagination d-inline-flex">
<f:comment><!-- First/Previous page --></f:comment>
<f:if condition="{pagination.previousPageNumber}">
<f:then>
<li class="page-item ps-2">
<f:be.link route="system_mailqueue"
parameters="{page: pagination.firstPageNumber}"
title="{f:translate(key: 'aria.first', extensionName: 'Mailqueue')}"
aria="{label: '{f:translate(key: \'aria.first\', extensionName: \'Mailqueue\')}'}"
>{c:icon(identifier: 'actions-view-paging-first')}</f:be.link>
</li>
<li class="page-item ps-2">
<f:be.link route="system_mailqueue"
parameters="{page: pagination.previousPageNumber}"
title="{f:translate(key: 'aria.previous', extensionName: 'Mailqueue')}"
aria="{label: '{f:translate(key: \'aria.previous\', extensionName: \'Mailqueue\')}'}"
>{c:icon(identifier: 'actions-view-paging-previous')}</f:be.link>
</li>
</f:then>
<f:else>
<li class="page-item ps-2" aria-hidden="true">
{c:icon(identifier: 'actions-view-paging-first')}
</li>
<li class="page-item ps-2" aria-hidden="true">
{c:icon(identifier: 'actions-view-paging-previous')}
</li>
</f:else>
</f:if>

<f:comment><!-- Page selector --></f:comment>
<li class="page-item ps-2">
<form action="{f:be.uri(route: 'system_mailqueue')}" method="post">
<label>
{f:translate(key: 'pagination.pageRange.start', extensionName: 'Mailqueue')}

<input type="number"
autocomplete="off"
name="page"
min="{pagination.firstPageNumber}"
max="{pagination.lastPageNumber}"
value="{paginator.currentPageNumber}"
size="3"
class="form-control form-control-sm paginator-input"
>
</label>
<span aria-hidden="true">
<f:translate key="pagination.pageRange.end" extensionName="Mailqueue" arguments="{
0: pagination.lastPageNumber
}" />
</span>
</form>
</li>

<f:comment><!-- Next/Last page --></f:comment>
<f:if condition="{pagination.nextPageNumber}">
<f:then>
<li class="page-item ps-2">
<f:be.link route="system_mailqueue"
parameters="{page: pagination.nextPageNumber}"
title="{f:translate(key: 'aria.next', extensionName: 'Mailqueue')}"
aria="{label: '{f:translate(key: \'aria.next\', extensionName: \'Mailqueue\')}'}"
>{c:icon(identifier: 'actions-view-paging-next')}</f:be.link>
</li>
<li class="page-item ps-2">
<f:be.link route="system_mailqueue"
parameters="{page: pagination.lastPageNumber}"
title="{f:translate(key: 'aria.last', extensionName: 'Mailqueue')}"
aria="{label: '{f:translate(key: \'aria.last\', extensionName: \'Mailqueue\')}'}"
>{c:icon(identifier: 'actions-view-paging-last')}</f:be.link>
</li>
</f:then>
<f:else>
<li class="page-item ps-2" aria-hidden="true">
{c:icon(identifier: 'actions-view-paging-next')}
</li>
<li class="page-item ps-2" aria-hidden="true">
{c:icon(identifier: 'actions-view-paging-last')}
</li>
</f:else>
</f:if>

<f:comment><!-- Reload --></f:comment>
<li class="page-item ps-2">
<f:be.link route="system_mailqueue"
parameters="{page: paginator.currentPageNumber}"
title="{f:translate(key: 'aria.reload', extensionName: 'Mailqueue')}"
aria="{label: '{f:translate(key: \'aria.reload\', extensionName: \'Mailqueue\')}'}"
>{c:icon(identifier: 'actions-refresh')}</f:be.link>
</li>
</ul>
</nav>
</td>
</tr>
</f:if>

</html>
5 changes: 4 additions & 1 deletion Resources/Private/Partials/List/Queue.html
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,13 @@ <h2>{f:translate(key: 'header.mails', extensionName: 'Mailqueue')}</h2>
</tr>
</thead>
<tbody>
<f:for each="{queue}" as="queueItem" iteration="iterator">
<f:for each="{paginator.paginatedItems}" as="queueItem" iteration="iterator">
<f:render partial="List/QueueItem" arguments="{queueItem: queueItem, iterator: iterator}" />
</f:for>
</tbody>
<tfoot>
<f:render partial="List/Pagination" arguments="{pagination: pagination, paginator: paginator}" />
</tfoot>
</table>
</div>
</f:then>
Expand Down
4 changes: 3 additions & 1 deletion Resources/Private/Templates/List.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ <h1>{f:translate(key: 'header.list', extensionName: 'Mailqueue')}</h1>
<f:render partial="List/Queue" arguments="{
failing: failing,
longestPendingInterval: longestPendingInterval,
queue: transport.mailQueue,
pagination: pagination,
paginator: paginator,
queue: queue,
sendResult: sendResult
}" />
</f:else>
Expand Down
2 changes: 2 additions & 0 deletions ext_conf_template.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# cat=pagination//10; type=int+; label=Number of mails to display on a single page in backend module list pagination
pagination.itemsPerPage = 20

0 comments on commit 21036c2

Please sign in to comment.