<?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\Tag; 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\Service\ConfigurationService; use SGalinski\SgNews\Service\HeaderMetaDataService; 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; /** * Controller that handles the overview page of categories and their news */ class OverviewController extends AbstractController { /** * @var CategoryRepository */ protected $categoryRepository; /** * @var TagRepository */ protected $tagRepository; /** * @var NewsRepository */ protected $newsRepository; /** * Initialize the overviewAction to set the currentPageBrowserPage parameter * * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException */ public function initializeOverviewAction(){ $currentPageBrowserPage = (int) GeneralUtility::_GP('tx_sgnews_pagebrowser')['currentPage']; if($currentPageBrowserPage > 0){ $this->request->setArgument('currentPageBrowserPage', $currentPageBrowserPage); } } /** * Renders the news overview * * @param array $newsFilter * @param int $currentPageBrowserPage * @return void * @throws \InvalidArgumentException * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException * @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException */ public function overviewAction(array $newsFilter = [], $currentPageBrowserPage = 0) { switch ((int) $this->settings['groupBy']) { case 1: $this->overviewWithCategories([], [], $newsFilter, $currentPageBrowserPage); break; case 2: $this->overviewWithTags([], [], $newsFilter, $currentPageBrowserPage); break; default: $this->forward('overviewWithoutCategories', NULL, NULL, $this->request->getArguments()); break; } } /** * Highlights the best fitting news in the meta data of the page * * @param array $categoryIds * @param array $tagIds * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException * @throws \InvalidArgumentException */ 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->getMetaDataForNews($highlightedNews, $category); } if ($highlightedNewsMetaData['image']) { HeaderMetaDataService::addOgImageToHeader($highlightedNewsMetaData['image']); } elseif ($highlightedNewsMetaData['teaserImage']) { HeaderMetaDataService::addOgImageToHeader($highlightedNewsMetaData['teaserImage']); } } /** * Renders the news overview grouped by categories * * @param array $newsByCategory * @param array $allNews * @param array $newsFilter * @param int $currentPageBrowserPage * @return void * @throws \InvalidArgumentException * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException * @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException */ protected function overviewWithCategories( array $newsByCategory = [], array $allNews = [], array $newsFilter = [], $currentPageBrowserPage = 0 ) { $newsLimitPerCategory = (int) $this->settings['newsLimit']; $this->categoryRepository->setDefaultOrderings(['sorting' => Query::ORDER_ASCENDING]); $offset = $this->calculatePaginationOffset($currentPageBrowserPage, $newsLimitPerCategory); if ($this->settings['onlyNewsWithinThisPageSection']) { $categories = $this->categoryRepository->findCategoriesInRootLine($GLOBALS['TSFE']->id); } else { $categories = $this->categoryRepository->findAll()->toArray(); } if (count($categories) <= 0) { return; } $startTime = (int) $this->settings['starttime']; $endTime = (int) $this->settings['endtime']; $configurationService = GeneralUtility::makeInstance(ConfigurationService::class); $sortBy = $configurationService->getConfiguration('sortBy', $this->settings); $sortDirection = $configurationService->getConfiguration('sortDirection', $this->settings); $categoryIds = []; $categoriesById = []; $newsMetaData = []; foreach ($categories as $category) { /** @var $category Category */ $categoryId = $category->getUid(); $categoryIdsForSelect = [$categoryId]; $categoryIds[] = $category->getUid(); $categoriesById[$categoryId] = $category; if ($category->_getProperty('_languageUid') > 0) { $originalLangCategory = $this->categoryRepository->findOriginalLanguageById($category->getUid()); if ($originalLangCategory) { $originalLangCategoryId = $originalLangCategory->getUid(); $categoryIdsForSelect[] = $originalLangCategoryId; $categoryIds[] = $originalLangCategoryId; $categoriesById[$originalLangCategoryId] = $originalLangCategory; } } $tagIds = NULL; if ($newsFilter['tag']) { $tagIds = [(int) $newsFilter['tag']]; } foreach ($categoryIdsForSelect as $categoryIdsForSelectId) { $news = $this->newsRepository->findAllSortedNewsByCategories( [$categoryIdsForSelectId], $newsLimitPerCategory, $offset, $sortBy, $tagIds, $startTime, $endTime, $sortDirection ); $newsMetaData[$categoryIdsForSelectId] = []; foreach ($news as $newsEntry) { /** @var News $newsEntry */ $categoryId = $newsEntry->getPid(); $category = $categoriesById[$categoryIdsForSelectId]; if (!$category) { // Category isn't visible. continue; } $data = $this->getMetaDataForNews($newsEntry, $category); $newsMetaData[$categoryIdsForSelectId][] = $data; } } } $maxNewsPerCategory = 0; foreach ($categoriesById as $categoryId => $category) { if (!isset($newsMetaData[$categoryId]) || count($newsMetaData[$categoryId]) <= 0) { // Hide empty categories. continue; } /** @var $category Category */ if (isset($newsByCategory[$categoryId])) { /** @var $category Category */ $newsByCategory[$categoryId]['newsMetaData'] = array_merge($newsByCategory[$categoryId]['newsMetaData'], $newsMetaData[$categoryId], $newsFilter); } else { $newsByCategory[$categoryId] = [ 'record' => $category, 'recordId' => $categoryId, 'recordType' => 'category', 'newsMetaData' => $newsMetaData[$categoryId], 'newsCount' => count($newsMetaData[$categoryId]) ]; } $maxNewsPerCategory = \max($maxNewsPerCategory, \count($newsByCategory[$categoryId]['newsMetaData'])); } $tagIds = NULL; if ($newsFilter['tag']) { $tagIds = [(int) $newsFilter['tag']]; } $news = $this->newsRepository->findAllSortedNewsByCategories( $categoryIds, $newsLimitPerCategory, $offset, $sortBy, $tagIds, $startTime, $endTime, $sortDirection ); foreach ($news as $newsEntry) { /** @var News $newsEntry */ $categoryId = $newsEntry->getPid(); $category = $categoriesById[$categoryId]; if (!$category) { // Category isn't visible. continue; } $data = $this->getMetaDataForNews($newsEntry, $category); $allNews[] = $data; } $this->highlightBestFitNews($categoryIds); $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; } } // find all tags $tagPid = $GLOBALS['TSFE']->id; if ($this->settings['onlyNewsWithinThisPageSection']) { $tags = $this->tagRepository->findTagsInRootLine($tagPid); } else { $tags = $this->tagRepository->findAll()->toArray(); } // remember selection of the filter values, if any $selectedTag = $this->tagRepository->findByUid((int) $newsFilter['tag']); $this->view->assign('selectedTag', $selectedTag); $this->view->assign('tags', $tags); $this->view->assign('categories', $categories); $this->view->assign('numberOfPages', $numberOfPages); $this->view->assign('newsItems', $newsByCategory); $this->view->assign('groupBy', 'category'); $this->view->assign('allNews', $allNews); $this->view->assign('categoryTabs', TRUE); } /** * Renders the news overview grouped by tags * * @param array $newsByTag * @param array $allNews * @param array $newsFilter * @param int $currentPageBrowserPage * @return void * @throws \InvalidArgumentException * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException * @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException */ protected function overviewWithTags( array $newsByTag = [], array $allNews = [], array $newsFilter = [], $currentPageBrowserPage = 0 ) { $startTime = (int) $this->settings['starttime']; $endTime = (int) $this->settings['endtime']; $newsLimitPerTag = (int) $this->settings['newsLimit']; $offset = $this->calculatePaginationOffset($currentPageBrowserPage, $newsLimitPerTag); $tagPid = (int) $this->settings['tagPid']; if (!$tagPid) { $tagPid = $GLOBALS['TSFE']->id; } $configurationService = GeneralUtility::makeInstance(ConfigurationService::class); $sortBy = $configurationService->getConfiguration('sortBy', $this->settings); $sortDirection = $configurationService->getConfiguration('sortDirection', $this->settings); $categoryIds = NULL; if ($newsFilter['category']) { $categoryIds = [(int) $newsFilter['category']]; } $this->tagRepository->setDefaultOrderings(['sorting' => QueryInterface::ORDER_ASCENDING]); if ($this->settings['onlyNewsWithinThisPageSection']) { $tags = $this->tagRepository->findTagsInRootLine($tagPid); } else { $tags = $this->tagRepository->findAll()->toArray(); } // Get news by tag id $tagIds = []; $tagsById = []; $categoriesById = []; $newsMetaData = []; foreach ($tags as $tag) { /** @var $tag Tag */ $tagId = $tag->getUid(); $tagIds[] = $tagId; $tagsById[$tagId] = $tag; $news = $this->newsRepository->findAllSortedNewsByCategories( $categoryIds, $newsLimitPerTag, $offset, $sortBy, [$tagId], $startTime, $endTime, $sortDirection ); $newsMetaData[$tagId] = []; foreach ($news as $newsEntry) { /** @var News $newsEntry */ $categoryId = $newsEntry->getPid(); if (!isset($categoriesById[$categoryId])) { $categoriesById[$categoryId] = $this->categoryRepository->findByUid($categoryId); } $category = $categoriesById[$categoryId]; if (!$category) { // Category isn't visible. continue; } $newsMetaData[$tagId][] = $this->getMetaDataForNews($newsEntry, $category); } } // Process news by tag id $maxNewsPerTag = 0; foreach ($tagsById as $tagId => $tag) { if (\count($newsMetaData[$tagId]) <= 0) { // Hide empty tags. continue; } if (isset($newsByTag[$tagId])) { $newsByTag[$tagId]['newsMetaData'] = \array_merge($newsByTag[$tagId]['newsMetaData'], $newsMetaData[$tagId]); } else { $newsByTag[$tagId] = [ 'record' => $tag, 'recordId' => $tagId, 'recordType' => 'tag', 'newsMetaData' => $newsMetaData[$tagId], 'newsCount' => \count($newsMetaData[$tagId]) ]; } $maxNewsPerTag = \max($maxNewsPerTag, \count($newsByTag[$tagId]['newsMetaData'])); } // Get all news by tags. $news = $this->newsRepository->findAllSortedNewsByCategories( $categoryIds, $newsLimitPerTag, $offset, $sortBy, $tagIds, $startTime, $endTime, $sortDirection ); foreach ($news as $newsEntry) { /** @var News $newsEntry */ $categoryId = $newsEntry->getPid(); if (!isset($categoriesById[$categoryId])) { $categoriesById[$categoryId] = $this->categoryRepository->findByUid($categoryId); } $category = $categoriesById[$categoryId]; if (!$category) { // Category isn't visible. continue; } $allNews[] = $this->getMetaDataForNews($newsEntry, $category); } $this->highlightBestFitNews([], $tagIds); // 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 ($this->settings['onlyNewsWithinThisPageSection']) { $categories = $this->categoryRepository->findCategoriesInRootLine($GLOBALS['TSFE']->id); } else { $categories = $this->categoryRepository->findAll()->toArray(); } // remember selection of the filter values, if any $selectedCategory = $this->categoryRepository->findByUid((int) $newsFilter['category']); $this->view->assign('selectedCategory', $selectedCategory); $this->view->assign('tags', $tags); $this->view->assign('categories', $categories); $this->view->assign('numberOfPages', $numberOfPages); $this->view->assign('newsItems', $newsByTag); $this->view->assign('groupBy', 'tag'); $this->view->assign('allNews', $allNews); $this->view->assign('tagTabs', TRUE); } /** * Initialize the overviewWithoutCategoriesAction to set the currentPageBrowserPage parameter * * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException */ public function initializeOverviewWithoutCategoriesAction(){ $currentPageBrowserPage = (int) GeneralUtility::_GP('tx_sgnews_pagebrowser')['currentPage']; if($currentPageBrowserPage > 0){ $this->request->setArgument('currentPageBrowserPage', $currentPageBrowserPage); } } /** * @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; } /** * Renders the news in a paginated list * * @param array $newsMetaData * @param array $newsFilter * @param int $currentPageBrowserPage * @return void * @throws \InvalidArgumentException * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException * @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException */ protected function overviewWithoutCategoriesAction( array $newsMetaData = [], array $newsFilter = NULL, $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']; $offset = $this->calculatePaginationOffset($currentPageBrowserPage, $newsPerPage); $newsCount = 0; $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 */ $categoriesById[$category->getUid()] = $category; $categoryIds[] = $category->getUid(); if ($category->_getProperty('_languageUid') > 0) { $originalLangCategory = $this->categoryRepository->findOriginalLanguageById($category->getUid()); if ($originalLangCategory) { $categoryIds[] = $originalLangCategory->getUid(); $categoriesById[$originalLangCategory->getUid()] = $originalLangCategory; } } } // 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); $categoryIds = NULL; $categoriesById = []; $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->getMetaDataForNews($newsEntry, $categoriesById[$newsEntry->getPid()]); $newsMetaData[] = $data; } $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; } } // find all tags $currentPageId = $GLOBALS['TSFE']->id; if ($this->settings['onlyNewsWithinThisPageSection']) { $tags = $this->tagRepository->findTagsInRootLine($currentPageId); } else { $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); } /** * Sets the pagebrowser page to the given new page. * * @param int $newPage * @return void */ protected function setPageBrowserPage($newPage) { $_GET['tx_sgnews_pagebrowser']['currentPage'] = $newPage; } }