Newer
Older
<?php
namespace SGalinski\SgNews\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!
***************************************************************/
use SGalinski\SgNews\Domain\Model\Category;
use SGalinski\SgNews\Domain\Model\News;
use SGalinski\SgNews\Domain\Repository\CategoryRepository;
use SGalinski\SgNews\Domain\Repository\NewsRepository;
use SGalinski\SgNews\Domain\Repository\TagRepository;
use SGalinski\SgNews\Domain\Service\NewsService;
use SGalinski\SgNews\Service\ConfigurationService;
use SGalinski\SgNews\Service\HeaderMetaDataService;
use SGalinski\SgSeo\Service\HeadTagService;
Stefan Galinski
committed
use TYPO3\CMS\Core\Http\ImmediateResponseException;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Persistence\Generic\QueryResult;
Fabian Galinski
committed
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
Stefan Galinski
committed
use TYPO3\CMS\Frontend\Controller\ErrorController;
use TYPO3\CMS\Frontend\Page\PageAccessFailureReasons;
/**
* Controller that handles the overview page of categories and their news
*/
class OverviewController extends AbstractController {
/**
/**
* @var NewsService
*/
protected $newsService;
Stefan Galinski
committed
/**
* @param CategoryRepository $categoryRepository
*/
public function injectCategoryRepository(CategoryRepository $categoryRepository
) {
$this->categoryRepository = $categoryRepository;
}
/**
* @param NewsRepository $newsRepository
*/
public function injectNewsRepository(NewsRepository $newsRepository) {
$this->newsRepository = $newsRepository;
}
/**
* @param TagRepository $tagRepository
*/
public function injectTagRepository(TagRepository $tagRepository) {
$this->tagRepository = $tagRepository;
}
/**
* @param NewsService $newsService
*/
public function injectNewsService(NewsService $newsService) {
$this->newsService = $newsService;
}
/**
* Initialize the overviewAction to set the currentPageBrowserPage parameter
*
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException
*/
Stefan Galinski
committed
public function initializeOverviewAction() {
$currentPageBrowserPage = (int) GeneralUtility::_GP('tx_sgnews_pagebrowser')['currentPage'];
Stefan Galinski
committed
if ($currentPageBrowserPage > 0) {
$this->request->setArgument('currentPageBrowserPage', $currentPageBrowserPage);
}
}
* @param array $newsFilter
* @param int $currentPageBrowserPage
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
* @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException
Stefan Galinski
committed
public function overviewAction(array $newsFilter = [], int $currentPageBrowserPage = 0) {
if ((int) $this->settings['groupBy'] === 0 && (bool) $this->settings['enableFilter'] === FALSE) {
$this->forward('overviewWithoutCategories', NULL, NULL, $this->request->getArguments());
// Setup settings
$startTime = (int) $this->settings['starttime'];
$endTime = (int) $this->settings['endtime'];
$newsLimit = (int) $this->settings['newsLimit'];
$offset = $this->calculatePaginationOffset($currentPageBrowserPage, $newsLimit);
$configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
$sortBy = $configurationService->getConfiguration('sortBy', $this->settings);
$sortDirection = $configurationService->getConfiguration('sortDirection', $this->settings);
$this->tagRepository->setDefaultOrderings(['sorting' => QueryInterface::ORDER_ASCENDING]);
$this->categoryRepository->setDefaultOrderings(['sorting' => QueryInterface::ORDER_ASCENDING]);
$useAllFilters = (bool) $this->settings['enableFilter'];
$isCategoryFiltered = $useAllFilters || (int) $this->settings['groupBy'] === 1;
$isTagFiltered = $useAllFilters || (int) $this->settings['groupBy'] === 2;
HeaderMetaDataService::addPageNumberToCanonical($currentPageBrowserPage);
// Get tag pid
$tagPid = (int) $this->settings['tagPid'];
if (!$tagPid) {
$tagPid = $GLOBALS['TSFE']->id;
}
if ($this->settings['onlyNewsWithinThisPageSection']) {
$categories = $this->categoryRepository->findCategoriesInRootLine($GLOBALS['TSFE']->id);
$tags = $this->tagRepository->findTagsInRootLine($tagPid);
} else {
$tags = $this->tagRepository->findAll()->toArray();
$categories = $this->categoryRepository->findAll()->toArray();
// Apply category restrictions
$categoryRestrictions = GeneralUtility::intExplode(',', $this->settings['categoryRestrictions'], TRUE);
if (!$isCategoryFiltered) {
$categoryRestrictions = [];
}
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($categoryId);
if ($originalLangCategory) {
$categoryIdTranslated = $originalLangCategory->getUid();
}
}
if (!in_array($categoryId, $categoryRestrictions, TRUE) &&
!in_array($categoryIdTranslated, $categoryRestrictions, TRUE)
) {
unset($categories[$key]);
}
}
}
// Apply tag restrictions
$tagRestrictions = GeneralUtility::intExplode(',', $this->settings['tagRestrictions'], TRUE);
if (!$isTagFiltered) {
$tagRestrictions = [];
}
if (count($tagRestrictions) > 0) {
foreach ($tags as $key => $tag) {
if (!in_array($tag->getUid(), $tagRestrictions, TRUE)) {
unset($tags[$key]);
}
}
}
// Get category ids or use the one in the filter
$categoryIds = [];
if ($newsFilter['category']) {
$categoryIds = [(int) $newsFilter['category']];
} elseif ($isCategoryFiltered) {
foreach ($categories as $category) {
$categoryIds[] = $category->getUid();
}
} else {
$categoryIds = NULL;
}
// Get tag ids or use the one in the filter
$tagIds = [];
if ($newsFilter['tag']) {
$tagIds = [(int) $newsFilter['tag']];
} elseif ($isTagFiltered) {
foreach ($tags as $tag) {
$tagIds[] = $tag->getUid();
}
} else {
$tagIds = NULL;
}
// Get all news by category and tag ids
$news = $this->newsRepository->findAllSortedNewsByCategories(
$categoryIds, $newsLimit, $offset, $sortBy, $tagIds, $startTime, $endTime, $sortDirection
// Process news result query based on filters
$allNews = [];
$newsItems = [];
$areCategoriesCreated = FALSE;
foreach ($news as $newsEntry) {
/** @var News $newsEntry */
$newsCategory = $this->categoryRepository->findOriginalLanguageById(
$newsEntry->getPid()
) ?? $this->categoryRepository->findByUid($newsEntry->getPid());
$newsCategoryId = $newsCategory->getUid();
$newsMetaData = $this->newsService->getMetaDataForNews($newsEntry, $newsCategory);
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
if ((int) $this->settings['groupBy'] === 1) {
if (!$areCategoriesCreated) {
// Add all required categories
foreach ($categories as $category) {
/** @var Category $category */
$newsItems[$category->getUid()] = [
'record' => $category,
'recordId' => $category->getUid(),
'recordType' => 'category',
'newsMetaData' => [],
'newsCount' => 0
];
}
$areCategoriesCreated = TRUE;
}
$newsItems[$newsCategoryId]['newsMetaData'][] = $newsMetaData;
$newsItems[$newsCategoryId]['newsCount'] += 1;
} else {
foreach ($tags as $tag) {
$tagId = $tag->getUid();
if (!isset($newsItems[$tagId])) {
$newsItems[$tagId] = [
'record' => $tag,
'recordId' => $tagId,
'recordType' => 'tag',
'newsMetaData' => [],
'newsCount' => 0
];
}
if ($newsEntry->getTags()->contains($tag)) {
$newsItems[$tagId]['newsMetaData'][] = $newsMetaData;
$newsItems[$tagId]['newsCount'] += 1;
}
}
$allNews[] = $newsMetaData;
$this->highlightBestFitNews($categoryIds, $tagIds);
// Check to achieve less Ajax calls.
$newsCount = $this->newsRepository->newsCountByCategories($categoryIds, $tagIds, $startTime, $endTime);
$numberOfPages = (int) ($newsLimit <= 0 ? 0 : ceil($newsCount / $newsLimit));
if ($numberOfPages !== 0 && $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);
}
// remember selection of the filter values, if any
$selectedTag = $this->tagRepository->findByUid((int) $newsFilter['tag']);
$selectedCategory = $this->categoryRepository->findByUid((int) $newsFilter['category']);
$this->view->assign('selectedCategory', $selectedCategory);
$this->view->assign('selectedTag', $selectedTag);
$this->view->assign('tags', $tags);
$this->view->assign('categories', $categories);
$this->view->assign('numberOfPages', $numberOfPages);
$this->view->assign('newsItems', $newsItems);
$this->view->assign('allNews', $allNews);
$this->setupGridColumns();
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
switch ($this->settings['groupBy']) {
case 1:
$this->view->assign('groupBy', 'category');
$this->view->assign('categoryTabs', TRUE);
break;
case 2:
$this->view->assign('groupBy', 'tag');
$this->view->assign('tagTabs', TRUE);
break;
default:
$this->view->assign('groupBy', 'none');
}
}
/**
* Assign the grid column classes to the frontend
*
* @return void
*/
protected function setupGridColumns(): void {
if (!isset($this->settings['gridColumns'])) {
$this->view->assign('gridColumnClasses', 'col-md-4 col-sm-6 col-xs-12');
return;
}
$columnAmount = (int) $this->settings['gridColumns'];
$columnClasses = '';
switch ($columnAmount) {
case 4:
$columnClasses .= 'col-lg-3 ';
case 3:
$columnClasses .= 'col-md-4 ';
case 2:
$columnClasses .= 'col-sm-6 ';
default:
$columnClasses .= 'col-xs-12';
}
$this->view->assign('gridColumnClasses', $columnClasses);
/**
* Highlights the best fitting news in the metadata of the page
*
Stefan Galinski
committed
* @param array|null $categoryIds
* @param array|null $tagIds
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
*/
protected function highlightBestFitNews(array $categoryIds = NULL, array $tagIds = NULL) {
$startTime = (int) $this->settings['starttime'];
$endTime = (int) $this->settings['endtime'];
/** @var News $highlightedNews */
$highlightedNews = $this->newsRepository
->findLastUpdatedOrHighlightedNewsByCategories(
1, FALSE, $categoryIds, 0, FALSE, $this->settings['sortBy'], $tagIds, $startTime, $endTime
)->getFirst();
if (!$highlightedNews) {
return;
}
/** @var Category $category */
$category = $this->categoryRepository->findByUid($highlightedNews->getPid());
$highlightedNewsMetaData = NULL;
if ($category) {
$highlightedNewsMetaData = $this->newsService->getMetaDataForNews($highlightedNews, $category);
}
if (!version_compare(ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) {
if ($highlightedNewsMetaData['image']) {
HeaderMetaDataService::addOgImageToHeader($highlightedNewsMetaData['image']);
} elseif ($highlightedNewsMetaData['teaserImage']) {
HeaderMetaDataService::addOgImageToHeader($highlightedNewsMetaData['teaserImage']);
}
}
}
/**
* Initialize the overviewWithoutCategoriesAction to set the currentPageBrowserPage parameter
*
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException
*/
Stefan Galinski
committed
public function initializeOverviewWithoutCategoriesAction() {
$currentPageBrowserPage = (int) GeneralUtility::_GP('tx_sgnews_pagebrowser')['currentPage'];
Stefan Galinski
committed
if ($currentPageBrowserPage > 0) {
$this->request->setArgument('currentPageBrowserPage', $currentPageBrowserPage);
}
}
/**
* Renders the news in a paginated list
*
* @param array $newsMetaData
* @param array|null $newsFilter
* @param int $currentPageBrowserPage
* @return void
Stefan Galinski
committed
* @throws ImmediateResponseException
* @throws \TYPO3\CMS\Core\Error\Http\PageNotFoundException
* @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
protected function overviewWithoutCategoriesAction(
Stefan Galinski
committed
array $newsMetaData = [], array $newsFilter = NULL, int $currentPageBrowserPage = 0
// remember selection of the filter values, if any
$selectedTag = $this->tagRepository->findByUid((int) $newsFilter['tag']);
$selectedCategory = $this->categoryRepository->findByUid((int) $newsFilter['category']);
$this->view->assign('selectedTag', $selectedTag);
$this->view->assign('selectedCategory', $selectedCategory);
$configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
$sortBy = $configurationService->getConfiguration('sortBy', $this->settings);
$sortDirection = $configurationService->getConfiguration('sortDirection', $this->settings);
$newsPerPage = (int) $this->settings['newsLimit'];
Fabian Galinski
committed
$offset = $this->calculatePaginationOffset($currentPageBrowserPage, $newsPerPage);
HeaderMetaDataService::addPageNumberToCanonical($currentPageBrowserPage);
$newsCount = 0;
Stefan Galinski
committed
$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 = [];
/** @var QueryResult $categories */
foreach ($categories as $category) {
/** @var Category $category */
$categoriesById[$category->getUid()] = $category;
$categoryIds[] = $category->getUid();
if ($category->_getProperty('_languageUid') > 0) {
Stefan Galinski
committed
$originalLangCategory = $this->categoryRepository->findOriginalLanguageById(
$category->getUid()
);
if ($originalLangCategory) {
$categoryIds[] = $originalLangCategory->getUid();
$categoriesById[$originalLangCategory->getUid()] = $originalLangCategory;
}
Kevin Ditscheid
committed
}
}
// filter by category and tag if selected in the filter
if ($newsFilter['category']) {
$categoryIds = [(int) $newsFilter['category']];
}
$tagIds = NULL;
if ($newsFilter['tag']) {
$tagIds = [(int) $newsFilter['tag']];
}
$newsCount = $this->newsRepository->newsCountByCategories($categoryIds, $tagIds, $startTime, $endTime);
}
} else {
$newsCount = $this->newsRepository->countAll($startTime, $endTime);
$categories = $this->categoryRepository->findAll()->toArray();
foreach ($categories as $category) {
/** @var Category $category */
$categoriesById[$category->getUid()] = $category;
}
if ($newsCount <= 0) {
return;
}
// filter by category and tag if selected in the filter
if ($newsFilter['category']) {
$categoryIds = [(int) $newsFilter['category']];
}
$tagIds = NULL;
if ($newsFilter['tag']) {
$tagIds = [(int) $newsFilter['tag']];
}
$news = $this->newsRepository->findAllSortedNewsByCategories(
$categoryIds, $newsPerPage, $offset, $sortBy, $tagIds, $startTime, $endTime, $sortDirection
);
foreach ($news as $newsEntry) {
/** @var News $newsEntry */
$data = $this->newsService->getMetaDataForNews($newsEntry, $categoriesById[$newsEntry->getPid()]);
$newsMetaData[] = $data;
}
$this->highlightBestFitNews($categoryIds);
Stefan Galinski
committed
$numberOfPages = (int) ($newsPerPage <= 0 ? 0 : ceil($newsCount / $newsPerPage));
if ($numberOfPages !== 0 && $currentPageBrowserPage >= $numberOfPages) {
Stefan Galinski
committed
/** @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']) {
$tags = $this->tagRepository->findTagsInRootLine($currentPageId);
$tags = $this->tagRepository->findAll()->toArray();
$this->view->assign('tags', $tags);
$this->view->assign('categories', $categories);
$this->view->assign('numberOfPages', $numberOfPages);
$this->view->assign('newsMetaData', $newsMetaData);
$this->setupGridColumns();
Fabian Galinski
committed
}
/**
* Sets the pagebrowser page to the given new page.
*
* @param int $newPage
* @return void
*/
protected function setPageBrowserPage($newPage) {
$_GET['tx_sgnews_pagebrowser']['currentPage'] = $newPage;