From c6fd9ba8d94ae670d8607ed6f9bb46f4d84e9dc5 Mon Sep 17 00:00:00 2001 From: Stefan Galinski <stefan@sgalinski.de> Date: Tue, 7 Sep 2021 19:26:32 +0200 Subject: [PATCH] [BUGFIX] Disallow pagination pages greater than the allowed max number of pages (SEO), Cleanup in parallel --- .../Controller/ListByCategoryController.php | 27 ++++--- Classes/Controller/OverviewController.php | 81 +++++++++++-------- .../Domain/Repository/CategoryRepository.php | 9 +-- 3 files changed, 67 insertions(+), 50 deletions(-) diff --git a/Classes/Controller/ListByCategoryController.php b/Classes/Controller/ListByCategoryController.php index 99c6281..609a754 100644 --- a/Classes/Controller/ListByCategoryController.php +++ b/Classes/Controller/ListByCategoryController.php @@ -32,7 +32,10 @@ use SGalinski\SgNews\Domain\Repository\NewsRepository; use SGalinski\SgNews\Domain\Repository\TagRepository; use SGalinski\SgNews\Service\ConfigurationService; use SGalinski\SgNews\Service\HeaderMetaDataService; +use TYPO3\CMS\Core\Http\ImmediateResponseException; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Frontend\Controller\ErrorController; +use TYPO3\CMS\Frontend\Page\PageAccessFailureReasons; /** * Controller that handles the list rendering of a single category @@ -96,8 +99,10 @@ class ListByCategoryController extends AbstractController { * @throws \InvalidArgumentException * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException * @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException + * @throws ImmediateResponseException + * @throws \TYPO3\CMS\Core\Error\Http\PageNotFoundException */ - public function indexAction(array $newsMetaData = [], $currentPageBrowserPage = 0) { + public function indexAction(array $newsMetaData = [], int $currentPageBrowserPage = 0) { $filterByCategories = FALSE; $categoryUids = GeneralUtility::intExplode(',', $this->settings['categories']); $tagUids = GeneralUtility::intExplode(',', $this->settings['tags'], TRUE); @@ -130,11 +135,20 @@ class ListByCategoryController extends AbstractController { $startTime = (int) $this->settings['starttime']; $endTime = (int) $this->settings['endtime']; - $newsPerPage = (int) $this->settings['newsLimitPerPage']; $newsCount = $this->newsRepository->newsCountByCategories($categoryUids, $tagUids, $startTime, $endTime); $numberOfPages = ($newsPerPage <= 0 ? 0 : ceil($newsCount / $newsPerPage)); + if ($currentPageBrowserPage >= $numberOfPages) { + /** @var ErrorController $errorController */ + $errorController = GeneralUtility::makeInstance(ErrorController::class); + $response = $errorController->pageNotFoundAction( + $GLOBALS['TYPO3_REQUEST'], + 'The requested page does not exist', + ['code' => PageAccessFailureReasons::PAGE_NOT_FOUND] + ); + throw new ImmediateResponseException($response); + } $headerSet = FALSE; $offset = $this->calculatePaginationOffset($currentPageBrowserPage, $newsPerPage); @@ -163,15 +177,6 @@ class ListByCategoryController extends AbstractController { } } - // Redo this function, until one variable get the amount of $newsPerPage. Reduces the amount of ajax calls. Needed because of languagevisibility. - if (count($newsMetaData) < $newsPerPage) { - $nextPage = $currentPageBrowserPage + 1; - if ($nextPage <= $numberOfPages) { - $this->indexAction($newsMetaData, $nextPage); - return; - } - } - $this->view->assign('numberOfPages', $numberOfPages); $this->view->assign('newsMetaData', $newsMetaData); $this->view->assign('categories', $categories); diff --git a/Classes/Controller/OverviewController.php b/Classes/Controller/OverviewController.php index 809957e..a43f8a2 100644 --- a/Classes/Controller/OverviewController.php +++ b/Classes/Controller/OverviewController.php @@ -27,17 +27,20 @@ namespace SGalinski\SgNews\Controller; ***************************************************************/ use SGalinski\SgNews\Domain\Model\Category; -use SGalinski\SgNews\Domain\Model\Tag; use SGalinski\SgNews\Domain\Model\News; +use SGalinski\SgNews\Domain\Model\Tag; use SGalinski\SgNews\Domain\Repository\CategoryRepository; use SGalinski\SgNews\Domain\Repository\NewsRepository; use SGalinski\SgNews\Domain\Repository\TagRepository; use SGalinski\SgNews\Service\ConfigurationService; use SGalinski\SgNews\Service\HeaderMetaDataService; +use TYPO3\CMS\Core\Http\ImmediateResponseException; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Persistence\Generic\Query; use TYPO3\CMS\Extbase\Persistence\Generic\QueryResult; use TYPO3\CMS\Extbase\Persistence\QueryInterface; +use TYPO3\CMS\Frontend\Controller\ErrorController; +use TYPO3\CMS\Frontend\Page\PageAccessFailureReasons; /** * Controller that handles the overview page of categories and their news @@ -162,6 +165,8 @@ class OverviewController extends AbstractController { * @throws \InvalidArgumentException * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException * @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException + * @throws ImmediateResponseException + * @throws \TYPO3\CMS\Core\Error\Http\PageNotFoundException */ protected function overviewWithCategories( array $newsByCategory = [], array $allNews = [], array $newsFilter = [], int $currentPageBrowserPage = 0 @@ -185,14 +190,19 @@ class OverviewController extends AbstractController { if (count($categoryRestrictions) > 0) { foreach ($categories as $key => $category) { $categoryId = $category->getUid(); + + // older version compatibility with selection of categories in translations and so on + $categoryIdTranslated = $categoryId; if ($category->_getProperty('_languageUid') > 0) { - $originalLangCategory = $this->categoryRepository->findOriginalLanguageById($category->getUid()); + $originalLangCategory = $this->categoryRepository->findOriginalLanguageById($categoryId); if ($originalLangCategory) { - $categoryId = $originalLangCategory->getUid(); + $categoryIdTranslated = $originalLangCategory->getUid(); } } - if (!in_array($categoryId, $categoryRestrictions, TRUE)) { + if (!in_array($categoryId, $categoryRestrictions, TRUE) && + !in_array($categoryIdTranslated, $categoryRestrictions, TRUE) + ) { unset($categories[$key]); } } @@ -303,14 +313,15 @@ class OverviewController extends AbstractController { $newsCount = $this->newsRepository->newsCountByCategories($categoryIds, $tagIds, $startTime, $endTime); $numberOfPages = ($newsLimitPerCategory <= 0 ? 0 : ceil($newsCount / $newsLimitPerCategory)); - // Redo this function, until one variable get the amount of newsLimitPerTag. Reduces the amount of ajax calls. Needed because of languagevisibility. - if ($maxNewsPerCategory < $newsLimitPerCategory && \count($allNews) < $newsLimitPerCategory) { - $nextPage = $currentPageBrowserPage + 1; - if ($nextPage <= $numberOfPages) { - $this->setPageBrowserPage($nextPage); - $this->overviewWithCategories($newsByCategory, $allNews, $newsFilter, $nextPage); - return; - } + if ($currentPageBrowserPage >= $numberOfPages) { + /** @var ErrorController $errorController */ + $errorController = GeneralUtility::makeInstance(ErrorController::class); + $response = $errorController->pageNotFoundAction( + $GLOBALS['TYPO3_REQUEST'], + 'The requested page does not exist', + ['code' => PageAccessFailureReasons::PAGE_NOT_FOUND] + ); + throw new ImmediateResponseException($response); } // find all tags @@ -344,6 +355,8 @@ class OverviewController extends AbstractController { * @throws \InvalidArgumentException * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException * @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException + * @throws ImmediateResponseException + * @throws \TYPO3\CMS\Core\Error\Http\PageNotFoundException */ protected function overviewWithTags( array $newsByTag = [], array $allNews = [], array $newsFilter = [], int $currentPageBrowserPage = 0 @@ -462,14 +475,15 @@ class OverviewController extends AbstractController { // Check to achieve less Ajax calls. $newsCount = $this->newsRepository->newsCountByCategories([], $tagIds, $startTime, $endTime); $numberOfPages = ($newsLimitPerTag <= 0 ? 0 : ceil($newsCount / $newsLimitPerTag)); - // Redo this function, until one variable get the amount of newsLimitPerTag. Reduces the amount of ajax calls. Needed because of languagevisibility. - if ($maxNewsPerTag < $newsLimitPerTag && \count($allNews) < $newsLimitPerTag) { - $nextPage = $currentPageBrowserPage + 1; - if ($nextPage <= $numberOfPages) { - $this->setPageBrowserPage($nextPage); - $this->overviewWithTags($newsByTag, $allNews, $newsFilter, $nextPage); - return; - } + if ($currentPageBrowserPage >= $numberOfPages) { + /** @var ErrorController $errorController */ + $errorController = GeneralUtility::makeInstance(ErrorController::class); + $response = $errorController->pageNotFoundAction( + $GLOBALS['TYPO3_REQUEST'], + 'The requested page does not exist', + ['code' => PageAccessFailureReasons::PAGE_NOT_FOUND] + ); + throw new ImmediateResponseException($response); } if ($this->settings['onlyNewsWithinThisPageSection']) { @@ -513,6 +527,8 @@ class OverviewController extends AbstractController { * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException * @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException + * @throws ImmediateResponseException + * @throws \TYPO3\CMS\Core\Error\Http\PageNotFoundException */ protected function overviewWithoutCategoriesAction( array $newsMetaData = [], array $newsFilter = NULL, int $currentPageBrowserPage = 0 @@ -531,13 +547,14 @@ class OverviewController extends AbstractController { $offset = $this->calculatePaginationOffset($currentPageBrowserPage, $newsPerPage); $newsCount = 0; + $categoryIds = NULL; + $categoriesById = []; $startTime = (int) $this->settings['starttime']; $endTime = (int) $this->settings['endtime']; if ($this->settings['onlyNewsWithinThisPageSection']) { $categories = $this->categoryRepository->findCategoriesInRootLine($GLOBALS['TSFE']->id); if (count($categories) > 0) { $categoryIds = []; - $categoriesById = []; /** @var QueryResult $categories */ foreach ($categories as $category) { /** @var $category Category */ @@ -568,9 +585,6 @@ class OverviewController extends AbstractController { } } else { $newsCount = $this->newsRepository->countAll($startTime, $endTime); - $categoryIds = NULL; - - $categoriesById = []; $categories = $this->categoryRepository->findAll()->toArray(); foreach ($categories as $category) { /** @var $category Category */ @@ -602,17 +616,16 @@ class OverviewController extends AbstractController { } $this->highlightBestFitNews($categoryIds); - $numberOfPages = ($newsPerPage <= 0 ? 0 : ceil($newsCount / $newsPerPage)); - - // Redo this function, until one variable get the amount of newsLimitPerTag. Reduces the amount of ajax calls. Needed because of languagevisibility. - if (\count($newsMetaData) < ($newsPerPage - 1)) { - $nextPage = $currentPageBrowserPage + 1; - if ($nextPage <= $numberOfPages) { - $this->setPageBrowserPage($nextPage); - $this->overviewWithoutCategoriesAction($newsMetaData, $newsFilter, $nextPage); - return; - } + if ($currentPageBrowserPage >= $numberOfPages) { + /** @var ErrorController $errorController */ + $errorController = GeneralUtility::makeInstance(ErrorController::class); + $response = $errorController->pageNotFoundAction( + $GLOBALS['TYPO3_REQUEST'], + 'The requested page does not exist', + ['code' => PageAccessFailureReasons::PAGE_NOT_FOUND] + ); + throw new ImmediateResponseException($response); } // find all tags diff --git a/Classes/Domain/Repository/CategoryRepository.php b/Classes/Domain/Repository/CategoryRepository.php index 81f0076..83d5324 100644 --- a/Classes/Domain/Repository/CategoryRepository.php +++ b/Classes/Domain/Repository/CategoryRepository.php @@ -51,7 +51,7 @@ class CategoryRepository extends AbstractRepository { * @param int $uid * @return Category|null */ - public function findOriginalLanguageById(int $uid) { + public function findOriginalLanguageById(int $uid): ?Category { $dataMapper = $this->objectManager->get(DataMapper::class); $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); $row = $queryBuilder->select('default.*') @@ -62,18 +62,17 @@ class CategoryRepository extends AbstractRepository { ) ->setMaxResults(1) ->execute()->fetch(); - if ($row) { + if ($row && (int) $row['uid'] !== 0) { return current($dataMapper->map($this->objectType, [$row])); - } else { - return NULL; } + + return NULL; } /** * Returns all categories, with given page id in it's rootline. * * @param int $pageId - * * @return array */ public function findCategoriesInRootLine(int $pageId): array { -- GitLab