Skip to content
Snippets Groups Projects
Commit c7666d25 authored by Matthias Adrowski's avatar Matthias Adrowski
Browse files

[TASK] Migrate Pagination

parent 27dbce51
No related branches found
No related tags found
1 merge request!35Feature upgrade to typo3 11
......@@ -28,13 +28,16 @@ namespace SGalinski\SgJobs\Controller;
use SGalinski\SgJobs\Domain\Repository\CompanyRepository;
use SGalinski\SgJobs\Domain\Repository\JobRepository;
use SGalinski\SgJobs\Paginator\QueryResultRawPaginator;
use SGalinski\SgJobs\Service\BackendService;
use TYPO3\CMS\Backend\Template\Components\DocHeaderComponent;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Pagination\SimplePagination;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Pagination\QueryResultPaginator;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
......@@ -89,7 +92,14 @@ class BackendController extends ActionController {
*/
public function indexAction(array $filters = []): ?\Psr\Http\Message\ResponseInterface {
$pageUid = (int) GeneralUtility::_GP('id');
$itemsPerPage = 10;
// Update Page in case we got a currentPage from Pagination
if($this->request->hasArgument('currentPage')){
$currentPage = (int) $this->request->getArgument('currentPage');
}
else {
$currentPage = 1;
}
/** @var BackendUserAuthentication $backendUser */
$backendUser = $GLOBALS['BE_USER'];
if ($filters === []) {
......@@ -132,8 +142,11 @@ class BackendController extends ActionController {
}
$this->view->assign('sortingData', $sortingData);
/** @var ObjectStorage $jobs */
$jobs = $this->jobRepository->findBackendJobs($pageUid, $filters);
$jobs = $this->jobRepository->findBackendJobs($pageUid, $filters, $itemsPerPage);
$paginator = new QueryResultRawPaginator($jobs);
$pagination = new SimplePagination($paginator);
$this->view->assign('paginator', $paginator);
$this->view->assign('pagination', $pagination);
$totalJobCount = \count($jobs);
// get all Locations
......@@ -153,8 +166,10 @@ class BackendController extends ActionController {
);
}
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
$this->view->assign('V11', FALSE);
return NULL;
} else {
$this->view->assign('V11', TRUE);
return $this->createBackendResponse();
}
}
......
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace SGalinski\SgJobs\Paginator;
use TYPO3\CMS\Core\Pagination\AbstractPaginator;
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
/**
* Copied QueryResult Paginator for us to get a raw result returned,
* just like the old Controller used to use, also alot of BE ViewHelpers want an array
*/
final class QueryResultRawPaginator extends AbstractPaginator {
/**
* @var QueryResultInterface
*/
private $queryResult;
/**
* @var QueryResultInterface
*/
private $paginatedQueryResult;
/**
* @var int
*/
protected int $totalItems = 0;
public function __construct(
QueryResultInterface $queryResult,
int $currentPageNumber = 1,
int $itemsPerPage = 10
) {
$this->queryResult = $queryResult;
$this->setCurrentPageNumber($currentPageNumber);
$this->setItemsPerPage($itemsPerPage);
$this->updateInternalState();
}
/**
* @return iterable|QueryResultInterface
*/
public function getPaginatedItems(): iterable {
return $this->paginatedQueryResult;
}
protected function updatePaginatedItems(int $limit, int $offset): void {
$this->paginatedQueryResult = $this->queryResult
->getQuery()
->setLimit($limit)
->setOffset($offset)
->execute(TRUE);
}
protected function getTotalAmountOfItems(): int {
$totalItems = $this->queryResult
->getQuery()
->setLimit(99999)
->setOffset(0)
->count();
$this->setTotalItems($totalItems);
return $totalItems;
}
protected function getAmountOfItemsOnCurrentPage(): int {
return count($this->paginatedQueryResult);
}
/**
* @return int
*/
public function getTotalItems(): int {
return $this->totalItems;
}
/**
* @param int $totalItems
*/
public function setTotalItems(int $totalItems): void {
$this->totalItems = $totalItems;
}
}
......@@ -43,7 +43,7 @@ class ControlViewHelper extends AbstractViewHelper {
public function initializeArguments(): void {
parent::initializeArguments();
$this->registerArgument('table', 'string', 'The table to control', TRUE);
$this->registerArgument('row', 'object', 'The row of the record', TRUE);
$this->registerArgument('row', 'array', 'The row of the record', TRUE);
}
/**
......@@ -55,11 +55,15 @@ class ControlViewHelper extends AbstractViewHelper {
$table = $this->arguments['table'];
/** @var Job $row */
$row = $this->arguments['row'];
$row = BackendUtility::getRecord('tx_sgjobs_domain_model_job', $row->getUid());
$row = BackendUtility::getRecord('tx_sgjobs_domain_model_job', $row['uid']);
$databaseRecordList = GeneralUtility::makeInstance(DatabaseRecordList::class);
$pageInfo = BackendUtility::readPageAccess($row['pid'], $GLOBALS['BE_USER']->getPagePermsClause(1));
$databaseRecordList->calcPerms = $GLOBALS['BE_USER']->calcPerms($pageInfo);
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
$databaseRecordList->calcPerms = $GLOBALS['BE_USER']->calcPerms($pageInfo);
} else {
$databaseRecordList->calcPerms = new \TYPO3\CMS\Core\Type\Bitmask\Permission($GLOBALS['BE_USER']->calcPerms($pageInfo));
}
$pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
$pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/AjaxDataHandler');
$pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_alt_doc.xlf');
......
......@@ -42,7 +42,7 @@ class IconViewHelper extends AbstractViewHelper {
public function initializeArguments(): void {
parent::initializeArguments();
$this->registerArgument('table', 'string', 'The table for the icon', TRUE);
$this->registerArgument('row', 'object', 'The row of the record', TRUE);
$this->registerArgument('row', 'array', 'The row of the record', TRUE);
$this->registerArgument('clickMenu', 'bool', 'Render a clickMenu around the icon', FALSE, TRUE);
}
......@@ -53,7 +53,7 @@ class IconViewHelper extends AbstractViewHelper {
*/
public function render(): string {
$row = $this->arguments['row'];
$row = BackendUtility::getRecord('tx_sgjobs_domain_model_job', $row->getUid());
$row = BackendUtility::getRecord('tx_sgjobs_domain_model_job', $row['uid']);
$table = $this->arguments['table'];
$clickMenu = $this->arguments['clickMenu'];
......
<?php
namespace SGalinski\SgJobs\ViewHelpers\Backend\Widget\Controller;
/***************************************************************
* Copyright notice
*
* (c) sgalinski Internet Services (https://www.sgalinski.de)
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project 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 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script 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.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
/**
* PaginateController
*/
class PaginateController extends \TYPO3\CMS\Fluid\ViewHelpers\Be\Widget\Controller\PaginateController {
/**
* @var mixed
*/
protected $objects;
/**
* Renders the paginator
*
* @param int $currentPage
* @return void
*/
public function indexAction($currentPage = 1) {
// set current page
$this->currentPage = (int) $currentPage;
if ($this->currentPage < 1) {
$this->currentPage = 1;
}
if ($this->currentPage > $this->numberOfPages) {
// set $modifiedObjects to NULL if the page does not exist
$modifiedObjects = NULL;
} else {
// modify query
$this->itemsPerPage = (int) $this->configuration['itemsPerPage'];
$this->offset = $this->itemsPerPage * ($this->currentPage - 1);
if (\is_array($this->objects)) {
$modifiedObjects = [];
for ($index = $this->offset; $index < $this->offset + $this->itemsPerPage; $index++) {
if (isset($this->objects[$index])) {
$modifiedObjects[] = $this->objects[$index];
} else {
break;
}
}
} else {
$query = $this->objects->getQuery();
$query->setLimit($this->itemsPerPage);
if ($this->currentPage > 1) {
$query->setOffset($this->offset);
}
$modifiedObjects = $query->execute();
}
}
$this->view->assign(
'contentArguments',
[
$this->widgetConfiguration['as'] => $modifiedObjects
]
);
$this->view->assign('configuration', $this->configuration);
$this->view->assign('pagination', $this->buildPagination());
}
/**
* Returns an array with the keys "pages", "current", "numberOfPages",
* "nextPage" & "previousPage"
*
* @return array
*/
protected function buildPagination() {
$pagination = parent::buildPagination();
$pagination['totalObjects'] = is_countable($this->objects) ? \count($this->objects) : 0;
return $pagination;
}
}
<?php
namespace SGalinski\SgJobs\ViewHelpers\Backend\Widget;
/***************************************************************
* Copyright notice
*
* (c) sgalinski Internet Services (https://www.sgalinski.de)
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project 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 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script 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.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use SGalinski\SgJobs\ViewHelpers\Backend\Widget\Controller\PaginateController;
use TYPO3\CMS\Fluid\Core\Widget\AbstractWidgetViewHelper;
/**
* Class PaginateViewHelper
*
* @package SGalinski\SgJobs\ViewHelpers\Backend\Widget
*/
class PaginateViewHelper extends AbstractWidgetViewHelper {
/**
* @var PaginateController
*/
protected $controller;
/**
* Initializes the controller
*
* @param PaginateController $controller
*/
public function injectPaginateController(PaginateController $controller): void {
$this->controller = $controller;
}
/**
* Register the ViewHelper arguments
*/
public function initializeArguments(): void {
parent::initializeArguments();
$this->registerArgument('objects', 'array', 'The objects to paginate', TRUE);
$this->registerArgument('as', 'string', 'The name of the variable inside the pagination', TRUE);
$this->registerArgument(
'configuration',
'array',
'The configuration of the pagination',
FALSE,
[
'itemsPerPage' => 10,
'insertAbove' => FALSE,
'insertBelow' => TRUE,
'recordsLabel' => ''
]
);
}
/**
* Renders the paginator
*
* @return string
*/
public function render(): string {
return $this->initiateSubRequest();
}
}
{namespace core = TYPO3\CMS\Core\ViewHelpers}
{namespace sg=SGalinski\SgJobs\ViewHelpers}
<f:be.container
includeCssFiles="{0: '{f:uri.resource(path: \'StyleSheets/backend.css\')}'}"
includeRequireJsModules="{
<f:if condition="{V11}">
<f:then>
<f:be.pageRenderer includeCssFiles="{0: '{f:uri.resource(path: \'StyleSheets/backend.css\')}'}"
includeRequireJsModules="{
0: 'TYPO3/CMS/Backend/ContextMenu',
1: 'TYPO3/CMS/Backend/Tooltip',
2: 'TYPO3/CMS/SgJobs/Backend/SgJobs'}"
/>
<h1>
<f:render section="headline"/>
</h1>
<f:render section="main"/>
</f:then>
<f:else>
<f:be.container
includeCssFiles="{0: '{f:uri.resource(path: \'StyleSheets/backend.css\')}'}"
includeRequireJsModules="{
0: 'TYPO3/CMS/Backend/ContextMenu',
1: 'TYPO3/CMS/Backend/Tooltip',
2: 'TYPO3/CMS/SgJobs/Backend/SgJobs'}">
<div class="module" data-module-id="" data-module-name="">
<div class="module-docheader t3js-module-docheader">
<div class="module-docheader-bar module-docheader-bar-navigation t3js-module-docheader-bar t3js-module-docheader-bar-navigation">
<div class="module-docheader-bar-column-left">
</div>
<div class="module-docheader-bar-column-right">
<div class="module" data-module-id="" data-module-name="">
<div class="module-docheader t3js-module-docheader">
<div
class="module-docheader-bar module-docheader-bar-navigation t3js-module-docheader-bar t3js-module-docheader-bar-navigation">
<div class="module-docheader-bar-column-left">
</div>
<div class="module-docheader-bar-column-right">
<span class="typo3-docheader-pagePath">
<f:translate key="LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.path" />: <f:format.raw>{docHeader.metaInformation.path}</f:format.raw>
<f:translate key="LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.path"/>: <f:format.raw>{docHeader.metaInformation.path}</f:format.raw>
</span>
<f:format.raw>{docHeader.metaInformation.recordInformation}</f:format.raw>
</div>
</div>
<div class="module-docheader-bar module-docheader-bar-buttons t3js-module-docheader-bar t3js-module-docheader-bar-buttons">
<div class="module-docheader-bar-column-left">
<div class="btn-toolbar" role="toolbar" aria-label="">
<f:render section="iconButtons" />
<f:format.raw>{docHeader.metaInformation.recordInformation}</f:format.raw>
</div>
</div>
<div
class="module-docheader-bar module-docheader-bar-buttons t3js-module-docheader-bar t3js-module-docheader-bar-buttons">
<div class="module-docheader-bar-column-left">
<div class="btn-toolbar" role="toolbar" aria-label="">
<f:render section="iconButtons"/>
</div>
</div>
<div class="module-docheader-bar-column-right">
<f:render partial="ButtonBar" arguments="{buttons:docHeader.buttons.right}"/>
</div>
</div>
</div>
<div class="module-docheader-bar-column-right">
<f:render partial="ButtonBar" arguments="{buttons:docHeader.buttons.right}" />
</div>
<div id="typo3-docbody">
<div id="typo3-inner-docbody">
<h1>
<f:render section="headline"/>
</h1>
<f:render section="main"/>
</div>
</div>
</div>
</div>
<div id="typo3-docbody">
<div id="typo3-inner-docbody">
<h1>
<f:render section="headline" />
</h1>
<f:render section="main" />
</div>
</div>
</f:be.container>
</f:be.container>
</f:else>
</f:if>
{namespace core=TYPO3\CMS\Core\ViewHelpers}
{namespace sg=SGalinski\SgMail\ViewHelpers}
<nav class="pagination-wrap">
<ul class="pagination pagination-block">
<f:if condition="{pagination.previousPageNumber} && {pagination.previousPageNumber} >= {pagination.firstPageNumber}">
<f:then>
<li>
<a href="{f:uri.action(action:actionName, arguments:{currentPage: 1})}" title="{f:translate(key:'widget.pagination.first')}">
<core:icon identifier="actions-view-paging-first" />
</a>
</li>
<li>
<a href="{f:uri.action(action:actionName, arguments:{currentPage: pagination.previousPageNumber})}" title="{f:translate(key:'widget.pagination.previous')}">
<core:icon identifier="actions-view-paging-previous" />
</a>
</li>
</f:then>
<f:else>
<li class="disabled">
<span>
<core:icon identifier="actions-view-paging-first" />
</span>
</li>
<li class="disabled">
<span>
<core:icon identifier="actions-view-paging-previous" />
</span>
</li>
</f:else>
</f:if>
<li>
<span>
<f:if condition="{recordsLabel}">
<f:then>
{recordsLabel}
</f:then>
<f:else>
<f:translate key="widget.pagination.records" />
</f:else>
</f:if>
{pagination.startRecordNumber} - {pagination.endRecordNumber} / {paginator.totalItems}
</span>
</li>
<li>
<span>
<f:translate key="widget.pagination.page" />
<form id="paginator-form-{position}" onsubmit="goToPage{position}(this); return false;" style="display:inline;">
<script type="text/javascript">
function goToPage{position}(formObject) {
var page = formObject.elements['paginator-target-page'].value;
var url = '{f:uri.action(action:actionName, arguments:{currentPage: 987654321}) -> f:format.raw()}';
if (page > {pagination.lastPageNumber}) {
page = {pagination.lastPageNumber};
}
else
if (page < 1) {
page = 1;
}
url = url.replace('987654321', page);
self.location.href = url;
}
</script>
<f:form.textfield id="paginator-{position}" name="paginator-target-page" additionalAttributes="{min: '1'}" class="form-control input-sm paginator-input" size="5" value="{currentPage}" type="number" />
</form>
/ {pagination.lastPageNumber}
</span>
</li>
<f:if condition="{pagination.nextPageNumber} && {pagination.nextPageNumber} <= {pagination.lastPageNumber}">
<f:then>
<li>
<a href="{f:uri.action(action:actionName, arguments:{currentPage: pagination.nextPageNumber})}" title="{f:translate(key:'widget.pagination.next')}">
<core:icon identifier="actions-view-paging-next" />
</a>
</li>
<li>
<a href="{f:uri.action(action:actionName, arguments:{currentPage: pagination.lastPageNumber})}" title="{f:translate(key:'widget.pagination.last')}">
<core:icon identifier="actions-view-paging-last" />
</a>
</li>
</f:then>
<f:else>
<li class="disabled">
<span>
<core:icon identifier="actions-view-paging-next" />
</span>
</li>
<li class="disabled">
<span>
<core:icon identifier="actions-view-paging-last" />
</span>
</li>
</f:else>
</f:if>
<li>
<a href="{f:uri.action(action:actionName, arguments:{currentPage: currentPage})}" title="{f:translate(key:'widget.pagination.refresh')}">
<core:icon identifier="actions-refresh" />
</a>
</li>
</ul>
</nav>
......@@ -32,9 +32,9 @@
<div class="panel panel-default recordlist">
<div class="table-fit">
<table data-table="tx_sgjobs_domain_model_job" class="table table-striped table-hover">
<sg:backend.widget.paginate objects="{jobs}" as="paginatedJobs" configuration="{insertAbove: 1, itemsPerPage: 20}">
<tbody>
<f:for each="{paginatedJobs}" as="job">
<tbody>
<f:render partial="Pagination" arguments="{pagination: pagination, paginator: paginator, actionName: 'index', currentPage: currentPage}"/>
<f:for each="{paginator.paginatedItems}" as="job">
<tr data-uid="{job.uid}">
<td nowrap="nowrap" class="col-icon">
<f:format.raw><sg:backend.icon table="tx_sgjobs_domain_model_job" row="{job}" /></f:format.raw>
......@@ -49,8 +49,7 @@
</td>
</tr>
</f:for>
</tbody>
</sg:backend.widget.paginate>
</tbody>
</table>
</div>
</div>
......
{namespace core=TYPO3\CMS\Core\ViewHelpers}
{namespace sg=SGalinski\SgJobs\ViewHelpers}
<f:if condition="{configuration.insertAbove}">
<thead>
<tr>
<td colspan="3">
<f:render section="paginator" arguments="{pagination: pagination, position:'top', recordsLabel: configuration.recordsLabel}" />
</td>
</tr>
</thead>
</f:if>
<f:renderChildren arguments="{contentArguments}" />
<f:if condition="{configuration.insertBelow}">
<tfoot>
<tr>
<td colspan="3">
<f:render section="paginator" arguments="{pagination: pagination, position:'bottom', recordsLabel: configuration.recordsLabel}" />
</td>
</tr>
</tfoot>
</f:if>
<f:section name="paginator">
<nav class="pagination-wrap">
<ul class="pagination pagination-block">
<f:if condition="{pagination.hasLessPages}">
<f:then>
<li>
<a href="{sg:widget.uri(arguments:{currentPage: 1})}" title="{f:translate(key:'widget.pagination.first')}">
<core:icon identifier="actions-view-paging-first" />
</a>
</li>
<li>
<a href="{sg:widget.uri(arguments:{currentPage: pagination.previousPage})}" title="{f:translate(key:'widget.pagination.previous')}">
<core:icon identifier="actions-view-paging-previous" />
</a>
</li>
</f:then>
<f:else>
<li class="disabled">
<span>
<core:icon identifier="actions-view-paging-first" />
</span>
</li>
<li class="disabled">
<span>
<core:icon identifier="actions-view-paging-previous" />
</span>
</li>
</f:else>
</f:if>
<li>
<span>
<f:if condition="{recordsLabel}">
<f:then>
{recordsLabel}
</f:then>
<f:else>
<f:translate key="widget.pagination.records" />
</f:else>
</f:if>
{pagination.startRecord} - {pagination.endRecord} / {pagination.totalObjects}
</span>
</li>
<li>
<span>
<f:translate key="widget.pagination.page" />
<form id="paginator-form-{position}" onsubmit="goToPage{position}(this); return false;" style="display:inline;">
<script type="text/javascript">
function goToPage{position}(formObject) {
var url = '{sg:widget.uri(arguments:{currentPage: 987654321}) -> f:format.raw()}';
var page = formObject.elements['paginator-target-page'].value;
if (page > {pagination.numberOfPages}) {
page = {pagination.numberOfPages};
} else if (page < 1) {
page = 1;
}
url = url.replace('987654321', page);
self.location.href= url;
}
</script>
<f:form.textfield id="paginator-{position}" name="paginator-target-page" additionalAttributes="{min: '1'}" class="form-control input-sm paginator-input" size="5" value="{pagination.current}" type="number" />
</form>
/ {pagination.numberOfPages}
</span>
</li>
<f:if condition="{pagination.hasMorePages}">
<f:then>
<li>
<a href="{sg:widget.uri(arguments:{currentPage: pagination.nextPage})}" title="{f:translate(key:'widget.pagination.next')}">
<core:icon identifier="actions-view-paging-next" />
</a>
</li>
<li>
<a href="{sg:widget.uri(arguments:{currentPage: pagination.numberOfPages})}" title="{f:translate(key:'widget.pagination.last')}">
<core:icon identifier="actions-view-paging-last" />
</a>
</li>
</f:then>
<f:else>
<li class="disabled">
<span>
<core:icon identifier="actions-view-paging-next" />
</span>
</li>
<li class="disabled">
<span>
<core:icon identifier="actions-view-paging-last" />
</span>
</li>
</f:else>
</f:if>
<li>
<a href="{sg:widget.uri(arguments:{currentPage: pagination.current})}" title="{f:translate(key:'widget.pagination.refresh')}">
<core:icon identifier="actions-refresh" />
</a>
</li>
</ul>
</nav>
</f:section>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment