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

Merge remote-tracking branch 'origin/master' into feature_Upgrade-to-TYPO3-11

parents d715b775 8ae4d306
No related branches found
No related tags found
1 merge request!38Feature upgrade to typo3 11
Showing
with 886 additions and 626 deletions
...@@ -27,32 +27,17 @@ namespace SGalinski\SgNews\Controller; ...@@ -27,32 +27,17 @@ namespace SGalinski\SgNews\Controller;
***************************************************************/ ***************************************************************/
use RuntimeException; use RuntimeException;
use SGalinski\SgNews\Domain\Model\Category;
use SGalinski\SgNews\Domain\Model\News;
use SGalinski\SgNews\Service\ImageService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
/** /**
* Abstract Controller * Abstract Controller
*/ */
abstract class AbstractController extends ActionController { abstract class AbstractController extends ActionController {
/**
* @var ImageService
*/
protected $imageService;
/** /**
* @var array * @var array
*/ */
protected $extensionConfiguration = []; protected $extensionConfiguration = [];
/**
* @var array
*/
protected $cachedSingleNews = [];
/** /**
* Initializes any action * Initializes any action
* *
...@@ -65,13 +50,6 @@ abstract class AbstractController extends ActionController { ...@@ -65,13 +50,6 @@ abstract class AbstractController extends ActionController {
parent::initializeAction(); parent::initializeAction();
} }
/**
* @param ImageService $imageService
*/
public function injectImageService(ImageService $imageService) {
$this->imageService = $imageService;
}
/** /**
* Error Handler * Error Handler
* *
...@@ -82,129 +60,6 @@ abstract class AbstractController extends ActionController { ...@@ -82,129 +60,6 @@ abstract class AbstractController extends ActionController {
throw new RuntimeException($this->getFlattenedValidationErrorMessage()); throw new RuntimeException($this->getFlattenedValidationErrorMessage());
} }
/**
* Returns the metadata of the given news.
*
* @param News $news
* @param Category $category
* @return array
* @throws \InvalidArgumentException
*/
protected function getMetaDataForNews(News $news, Category $category): array {
$newsId = $news->getUid();
if (isset($this->cachedSingleNews[$newsId])) {
return $this->cachedSingleNews[$newsId];
}
$fileRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\FileRepository::class);
$fileObjects = $fileRepository->findByRelation('pages', 'media', $news->getUid());
$singleNewsImageData = $this->getDataForSingleViewImage($news, $category);
$teaserImageData = $this->getDataForTeaserImage($news, $category);
// Use single news image data for teaser image data, if the teaser imaga data are empty.
$teaserIsEmpty = $teaserImageData['teaserImage'] === NULL && $teaserImageData['teaserImageObject'] === NULL;
$singleNewsIsEmpty = $singleNewsImageData['image'] === NULL && $singleNewsImageData['imageObject'] === NULL;
if ($teaserIsEmpty && !$singleNewsIsEmpty) {
$teaserImageData = [
'teaserImage' => $singleNewsImageData['image'],
'teaserImageObject' => $singleNewsImageData['imageObject'],
];
}
$newsRecord = array_merge(
[
'category' => $category,
'news' => $news,
],
$singleNewsImageData,
$teaserImageData,
['media' => $fileObjects]
);
$this->cachedSingleNews[$newsId] = $newsRecord;
return $newsRecord;
}
/**
* Returns the single view image data as an array for the given news and category as fallback.
*
* @param News $news
* @param Category $category
* @return array
* @throws \InvalidArgumentException
*/
protected function getDataForSingleViewImage(News $news, Category $category): array {
/** @var FileReference $singleNewsImage */
$singleNewsImage = $singleNewsImageObject = NULL;
$singleNewsImages = $news->getTeaser2Image();
if (count($singleNewsImages)) {
$singleNewsImage = $singleNewsImages->current();
} else {
$categoryImages = $category->getTeaser2Image();
if (count($categoryImages)) {
$singleNewsImage = $categoryImages->current();
}
}
if ($singleNewsImage) {
$singleNewsImageObject = $singleNewsImage;
$originalResource = $singleNewsImage->getOriginalResource();
if ($originalResource) {
$singleNewsImage = $originalResource->getPublicUrl();
}
if ($singleNewsImage) {
$singleNewsImage = $GLOBALS['TSFE']->absRefPrefix . $singleNewsImage;
}
}
return [
'image' => $singleNewsImage,
'imageObject' => $singleNewsImageObject,
];
}
/**
* Returns the teaser image data as an array for the given news and category as fallback.
*
* @param News $news
* @param Category $category
* @return array
* @throws \InvalidArgumentException
*/
protected function getDataForTeaserImage(News $news, Category $category): array {
/** @var FileReference $teaserImage */
$teaserImage = $teaserImageObject = NULL;
$teaserImages = $news->getTeaser1Image();
if (count($teaserImages)) {
$teaserImage = $teaserImages->current();
} else {
$categoryImages = $category->getTeaser1Image();
if (count($categoryImages)) {
$teaserImage = $categoryImages->current();
}
}
if ($teaserImage) {
$teaserImageObject = $teaserImage;
$originalResource = $teaserImage->getOriginalResource();
if ($originalResource) {
$teaserImage = $originalResource->getPublicUrl();
}
if ($teaserImage) {
$teaserImage = $GLOBALS['TSFE']->absRefPrefix . $teaserImage;
}
}
return [
'teaserImage' => $teaserImage,
'teaserImageObject' => $teaserImageObject,
];
}
/** /**
* Calculate the pagination offset * Calculate the pagination offset
* *
......
...@@ -31,6 +31,7 @@ use SGalinski\SgNews\Domain\Model\News; ...@@ -31,6 +31,7 @@ use SGalinski\SgNews\Domain\Model\News;
use SGalinski\SgNews\Domain\Repository\CategoryRepository; use SGalinski\SgNews\Domain\Repository\CategoryRepository;
use SGalinski\SgNews\Domain\Repository\NewsRepository; use SGalinski\SgNews\Domain\Repository\NewsRepository;
use SGalinski\SgNews\Domain\Repository\TagRepository; use SGalinski\SgNews\Domain\Repository\TagRepository;
use SGalinski\SgNews\Domain\Service\NewsService;
use SGalinski\SgNews\Service\ConfigurationService; use SGalinski\SgNews\Service\ConfigurationService;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
...@@ -53,6 +54,11 @@ class LatestController extends AbstractController { ...@@ -53,6 +54,11 @@ class LatestController extends AbstractController {
*/ */
protected $newsRepository; protected $newsRepository;
/**
* @var NewsService
*/
protected $newsService;
/** /**
* Renders the news overview * Renders the news overview
* *
...@@ -124,7 +130,7 @@ class LatestController extends AbstractController { ...@@ -124,7 +130,7 @@ class LatestController extends AbstractController {
$categories[$categoryUid] = $category; $categories[$categoryUid] = $category;
} }
$newsMetaData[] = $this->getMetaDataForNews($latestNewsEntry, $category); $newsMetaData[] = $this->newsService->getMetaDataForNews($latestNewsEntry, $category);
// Make sure, that the amount is the same as the configured limit. // Make sure, that the amount is the same as the configured limit.
if (count($newsMetaData) >= $limit) { if (count($newsMetaData) >= $limit) {
break; break;
...@@ -161,4 +167,11 @@ class LatestController extends AbstractController { ...@@ -161,4 +167,11 @@ class LatestController extends AbstractController {
public function injectTagRepository(TagRepository $tagRepository) { public function injectTagRepository(TagRepository $tagRepository) {
$this->tagRepository = $tagRepository; $this->tagRepository = $tagRepository;
} }
/**
* @param NewsService $newsService
*/
public function injectNewsService(NewsService $newsService) {
$this->newsService = $newsService;
}
} }
...@@ -30,6 +30,7 @@ use SGalinski\SgNews\Domain\Model\News; ...@@ -30,6 +30,7 @@ use SGalinski\SgNews\Domain\Model\News;
use SGalinski\SgNews\Domain\Repository\CategoryRepository; use SGalinski\SgNews\Domain\Repository\CategoryRepository;
use SGalinski\SgNews\Domain\Repository\NewsRepository; use SGalinski\SgNews\Domain\Repository\NewsRepository;
use SGalinski\SgNews\Domain\Repository\TagRepository; use SGalinski\SgNews\Domain\Repository\TagRepository;
use SGalinski\SgNews\Domain\Service\NewsService;
use SGalinski\SgNews\Service\ConfigurationService; use SGalinski\SgNews\Service\ConfigurationService;
use SGalinski\SgNews\Service\HeaderMetaDataService; use SGalinski\SgNews\Service\HeaderMetaDataService;
use TYPO3\CMS\Core\Http\ImmediateResponseException; use TYPO3\CMS\Core\Http\ImmediateResponseException;
...@@ -57,6 +58,11 @@ class ListByCategoryController extends AbstractController { ...@@ -57,6 +58,11 @@ class ListByCategoryController extends AbstractController {
*/ */
protected $newsRepository; protected $newsRepository;
/**
* @var NewsService
*/
protected $newsService;
/** /**
* @param CategoryRepository $categoryRepository * @param CategoryRepository $categoryRepository
*/ */
...@@ -80,6 +86,13 @@ class ListByCategoryController extends AbstractController { ...@@ -80,6 +86,13 @@ class ListByCategoryController extends AbstractController {
$this->tagRepository = $tagRepository; $this->tagRepository = $tagRepository;
} }
/**
* @param NewsService $newsService
*/
public function injectNewsService(NewsService $newsService) {
$this->newsService = $newsService;
}
/** /**
* Initialize the indexAction to set the currentPageBrowserPage parameter * Initialize the indexAction to set the currentPageBrowserPage parameter
* *
...@@ -186,7 +199,7 @@ class ListByCategoryController extends AbstractController { ...@@ -186,7 +199,7 @@ class ListByCategoryController extends AbstractController {
foreach ($news as $newsEntry) { foreach ($news as $newsEntry) {
/** @var News $newsEntry */ /** @var News $newsEntry */
$data = $this->getMetaDataForNews($newsEntry, $categories[$newsEntry->getPid()]); $data = $this->newsService->getMetaDataForNews($newsEntry, $categories[$newsEntry->getPid()]);
$newsMetaData[] = $data; $newsMetaData[] = $data;
if (!$headerSet) { if (!$headerSet) {
......
...@@ -32,6 +32,7 @@ use SGalinski\SgNews\Domain\Model\News; ...@@ -32,6 +32,7 @@ use SGalinski\SgNews\Domain\Model\News;
use SGalinski\SgNews\Domain\Repository\AuthorRepository; use SGalinski\SgNews\Domain\Repository\AuthorRepository;
use SGalinski\SgNews\Domain\Repository\CategoryRepository; use SGalinski\SgNews\Domain\Repository\CategoryRepository;
use SGalinski\SgNews\Domain\Repository\NewsRepository; use SGalinski\SgNews\Domain\Repository\NewsRepository;
use SGalinski\SgNews\Domain\Service\NewsService;
use SGalinski\SgSeo\Service\HeadTagService; use SGalinski\SgSeo\Service\HeadTagService;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
...@@ -40,6 +41,18 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; ...@@ -40,6 +41,18 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
* News Author List Controller * News Author List Controller
*/ */
class NewsByAuthorController extends AbstractController { class NewsByAuthorController extends AbstractController {
/**
* @var NewsService
*/
protected $newsService;
/**
* @param NewsService $newsService
*/
public function injectNewsService(NewsService $newsService) {
$this->newsService = $newsService;
}
/** /**
* Renders the news author list. * Renders the news author list.
* *
...@@ -130,7 +143,7 @@ class NewsByAuthorController extends AbstractController { ...@@ -130,7 +143,7 @@ class NewsByAuthorController extends AbstractController {
$categories[$categoryId] = $category; $categories[$categoryId] = $category;
} }
$newsMetaData[] = $this->getMetaDataForNews($newsEntry, $categories[$categoryId]); $newsMetaData[] = $this->newsService->getMetaDataForNews($newsEntry, $categories[$categoryId]);
} }
} }
......
...@@ -28,16 +28,15 @@ namespace SGalinski\SgNews\Controller; ...@@ -28,16 +28,15 @@ namespace SGalinski\SgNews\Controller;
use SGalinski\SgNews\Domain\Model\Category; use SGalinski\SgNews\Domain\Model\Category;
use SGalinski\SgNews\Domain\Model\News; use SGalinski\SgNews\Domain\Model\News;
use SGalinski\SgNews\Domain\Model\Tag;
use SGalinski\SgNews\Domain\Repository\CategoryRepository; use SGalinski\SgNews\Domain\Repository\CategoryRepository;
use SGalinski\SgNews\Domain\Repository\NewsRepository; use SGalinski\SgNews\Domain\Repository\NewsRepository;
use SGalinski\SgNews\Domain\Repository\TagRepository; use SGalinski\SgNews\Domain\Repository\TagRepository;
use SGalinski\SgNews\Domain\Service\NewsService;
use SGalinski\SgNews\Service\ConfigurationService; use SGalinski\SgNews\Service\ConfigurationService;
use SGalinski\SgNews\Service\HeaderMetaDataService; use SGalinski\SgNews\Service\HeaderMetaDataService;
use TYPO3\CMS\Core\Http\ImmediateResponseException; use TYPO3\CMS\Core\Http\ImmediateResponseException;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility; 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\Generic\QueryResult;
use TYPO3\CMS\Extbase\Persistence\QueryInterface; use TYPO3\CMS\Extbase\Persistence\QueryInterface;
use TYPO3\CMS\Frontend\Controller\ErrorController; use TYPO3\CMS\Frontend\Controller\ErrorController;
...@@ -62,11 +61,15 @@ class OverviewController extends AbstractController { ...@@ -62,11 +61,15 @@ class OverviewController extends AbstractController {
*/ */
protected $newsRepository; protected $newsRepository;
/**
* @var NewsService
*/
protected $newsService;
/** /**
* @param CategoryRepository $categoryRepository * @param CategoryRepository $categoryRepository
*/ */
public function injectCategoryRepository( public function injectCategoryRepository(CategoryRepository $categoryRepository
CategoryRepository $categoryRepository
) { ) {
$this->categoryRepository = $categoryRepository; $this->categoryRepository = $categoryRepository;
} }
...@@ -85,15 +88,20 @@ class OverviewController extends AbstractController { ...@@ -85,15 +88,20 @@ class OverviewController extends AbstractController {
$this->tagRepository = $tagRepository; $this->tagRepository = $tagRepository;
} }
/**
* @param NewsService $newsService
*/
public function injectNewsService(NewsService $newsService) {
$this->newsService = $newsService;
}
/** /**
* Initialize the overviewAction to set the currentPageBrowserPage parameter * Initialize the overviewAction to set the currentPageBrowserPage parameter
* *
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException
*/ */
public function initializeOverviewAction() { public function initializeOverviewAction() {
$currentPageBrowserPage = GeneralUtility::_GP('tx_sgnews_pagebrowser') ? (int) GeneralUtility::_GP( $currentPageBrowserPage = (int) GeneralUtility::_GP('tx_sgnews_pagebrowser')['currentPage'];
'tx_sgnews_pagebrowser'
)['currentPage'] : 0;
if ($currentPageBrowserPage > 0) { if ($currentPageBrowserPage > 0) {
$this->request->setArgument('currentPageBrowserPage', $currentPageBrowserPage); $this->request->setArgument('currentPageBrowserPage', $currentPageBrowserPage);
} }
...@@ -104,288 +112,171 @@ class OverviewController extends AbstractController { ...@@ -104,288 +112,171 @@ class OverviewController extends AbstractController {
* *
* @param array $newsFilter * @param array $newsFilter
* @param int $currentPageBrowserPage * @param int $currentPageBrowserPage
* @return void
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
* @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException * @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException
*/ */
public function overviewAction(array $newsFilter = [], int $currentPageBrowserPage = 0 public function overviewAction(array $newsFilter = [], int $currentPageBrowserPage = 0) {
): ?\Psr\Http\Message\ResponseInterface { if ((int) $this->settings['groupBy'] === 0 && (bool) $this->settings['enableFilter'] === FALSE) {
switch ((int) $this->settings['groupBy']) { $this->forward('overviewWithoutCategories', NULL, NULL, $this->request->getArguments());
case 1:
$this->overviewWithCategories([], [], $newsFilter, $currentPageBrowserPage);
break;
case 2:
$this->overviewWithTags([], [], $newsFilter, $currentPageBrowserPage);
break;
default:
if (version_compare(
\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<'
)) {
$this->forward('overviewWithoutCategories', NULL, NULL, $this->request->getArguments());
} else {
return (new \TYPO3\CMS\Extbase\Http\ForwardResponse(
'overviewWithoutCategories'
))->withControllerName('Record')
->withExtensionName('Extension')
->withArguments($this->request->getArguments());
}
break;
}
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
return NULL;
} else {
return $this->htmlResponse();
}
}
/**
* Highlights the best fitting news in the metadata of the page
*
* @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 = 0;
if (isset($this->settings['starttime'])) {
$startTime = (int) $this->settings['starttime'];
} }
$endTime = 0; // Setup settings
if (isset($this->settings['endtime'])) { $startTime = (int) $this->settings['starttime'];
$endTime = (int) $this->settings['endtime']; $endTime = (int) $this->settings['endtime'];
} $newsLimit = (int) $this->settings['newsLimit'];
$offset = $this->calculatePaginationOffset($currentPageBrowserPage, $newsLimit);
/** @var News $highlightedNews */ $configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
$highlightedNews = $this->newsRepository $sortBy = $configurationService->getConfiguration('sortBy', $this->settings);
->findLastUpdatedOrHighlightedNewsByCategories( $sortDirection = $configurationService->getConfiguration('sortDirection', $this->settings);
1, $this->tagRepository->setDefaultOrderings(['sorting' => QueryInterface::ORDER_ASCENDING]);
FALSE, $this->categoryRepository->setDefaultOrderings(['sorting' => QueryInterface::ORDER_ASCENDING]);
$categoryIds, $useAllFilters = (bool) $this->settings['enableFilter'];
0, $isCategoryFiltered = $useAllFilters || (int) $this->settings['groupBy'] === 1;
FALSE, $isTagFiltered = $useAllFilters || (int) $this->settings['groupBy'] === 2;
$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 (!version_compare(ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) { // Get tag pid
if (isset($highlightedNewsMetaData['imageObject'])) { $tagPid = (int) $this->settings['tagPid'];
HeaderMetaDataService::addOgImageObjectToHeader( if (!$tagPid) {
$highlightedNewsMetaData['imageObject'] $tagPid = $GLOBALS['TSFE']->id;
? $highlightedNewsMetaData['imageObject']->getOriginalResource()
: NULL
);
} elseif (isset($highlightedNewsMetaData['teaserImageObject'])) {
HeaderMetaDataService::addOgImageObjectToHeader(
$highlightedNewsMetaData['teaserImageObject']
? $highlightedNewsMetaData['teaserImageObject']->getOriginalResource()
: NULL
);
}
} }
}
/**
* 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
* @throws ImmediateResponseException
* @throws \TYPO3\CMS\Core\Error\Http\PageNotFoundException
*/
protected function overviewWithCategories(
array $newsByCategory = [],
array $allNews = [],
array $newsFilter = [],
int $currentPageBrowserPage = 0
) {
$newsLimitPerCategory = (int) $this->settings['newsLimit'];
$this->categoryRepository->setDefaultOrderings(['sorting' => Query::ORDER_ASCENDING]);
$offset = $this->calculatePaginationOffset($currentPageBrowserPage, $newsLimitPerCategory);
if ($this->settings['onlyNewsWithinThisPageSection']) { if ($this->settings['onlyNewsWithinThisPageSection']) {
$categories = $this->categoryRepository->findCategoriesInRootLine($GLOBALS['TSFE']->id); $categories = $this->categoryRepository->findCategoriesInRootLine($GLOBALS['TSFE']->id);
$tags = $this->tagRepository->findTagsInRootLine($tagPid);
} else { } else {
$tags = $this->tagRepository->findAll()->toArray();
$categories = $this->categoryRepository->findAll()->toArray(); $categories = $this->categoryRepository->findAll()->toArray();
} }
if (count($categories) <= 0) { // Apply category restrictions
return; $categoryRestrictions = GeneralUtility::intExplode(',', $this->settings['categoryRestrictions'], TRUE);
if (!$isCategoryFiltered) {
$categoryRestrictions = [];
} }
if (count($categoryRestrictions) > 0) {
foreach ($categories as $key => $category) {
$categoryId = $category->getUid();
if (isset($this->settings['categoryRestrictions'])) { // older version compatibility with selection of categories in translations and so on
$categoryRestrictions = GeneralUtility::intExplode(',', $this->settings['categoryRestrictions'], TRUE); $categoryIdTranslated = $categoryId;
if (count($categoryRestrictions) > 0) { if ($category->_getProperty('_languageUid') > 0) {
foreach ($categories as $key => $category) { $originalLangCategory = $this->categoryRepository->findOriginalLanguageById($categoryId);
$categoryId = $category->getUid(); if ($originalLangCategory) {
$categoryIdTranslated = $originalLangCategory->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) && if (!in_array($categoryId, $categoryRestrictions, TRUE) &&
!in_array($categoryIdTranslated, $categoryRestrictions, TRUE) !in_array($categoryIdTranslated, $categoryRestrictions, TRUE)
) { ) {
unset($categories[$key]); unset($categories[$key]);
}
} }
} }
} }
if (count($categories) <= 0) { // Apply tag restrictions
return; $tagRestrictions = GeneralUtility::intExplode(',', $this->settings['tagRestrictions'], TRUE);
} if (!$isTagFiltered) {
$tagRestrictions = [];
$startTime = 0;
if (isset($this->settings['starttime'])) {
$startTime = (int) $this->settings['starttime'];
}
$endTime = 0;
if (isset($this->settings['endtime'])) {
$endTime = (int) $this->settings['endtime'];
} }
if (count($tagRestrictions) > 0) {
$configurationService = GeneralUtility::makeInstance(ConfigurationService::class); foreach ($tags as $key => $tag) {
$sortBy = $configurationService->getConfiguration('sortBy', $this->settings); if (!in_array($tag->getUid(), $tagRestrictions, TRUE)) {
$sortDirection = $configurationService->getConfiguration('sortDirection', $this->settings); unset($tags[$key]);
$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 (isset($newsFilter['tag']) && $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 */
$category = $categoriesById[$categoryIdsForSelectId];
if (!$category) {
// Category isn't visible.
continue;
}
$data = $this->getMetaDataForNews($newsEntry, $category);
$newsMetaData[$categoryIdsForSelectId][] = $data;
} }
} }
} }
$maxNewsPerCategory = 0; // Get category ids or use the one in the filter
foreach ($categoriesById as $categoryId => $category) { $categoryIds = [];
if (!isset($newsMetaData[$categoryId]) || count($newsMetaData[$categoryId]) <= 0) { if ($newsFilter['category']) {
// Hide empty categories. $categoryIds = [(int) $newsFilter['category']];
continue; } elseif ($isCategoryFiltered) {
} foreach ($categories as $category) {
$categoryIds[] = $category->getUid();
/** @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])
];
} }
} else {
$maxNewsPerCategory = \max($maxNewsPerCategory, \count($newsByCategory[$categoryId]['newsMetaData'])); $categoryIds = NULL;
} }
$tagIds = NULL; // Get tag ids or use the one in the filter
if (isset($newsFilter['tag']) && $newsFilter['tag']) { $tagIds = [];
if ($newsFilter['tag']) {
$tagIds = [(int) $newsFilter['tag']]; $tagIds = [(int) $newsFilter['tag']];
} elseif ($isTagFiltered) {
foreach ($tags as $tag) {
$tagIds[] = $tag->getUid();
}
} else {
$tagIds = NULL;
} }
if ($newsFilter['category']) {
$categoryIds = [(int) $newsFilter['category']]; // Get all news by category and tag ids
}
$news = $this->newsRepository->findAllSortedNewsByCategories( $news = $this->newsRepository->findAllSortedNewsByCategories(
$categoryIds, $categoryIds, $newsLimit, $offset, $sortBy, $tagIds, $startTime, $endTime, $sortDirection
$newsLimitPerCategory,
$offset,
$sortBy,
$tagIds,
$startTime,
$endTime,
$sortDirection
); );
// Process news result query based on filters
$allNews = [];
$newsItems = [];
$areCategoriesCreated = FALSE;
foreach ($news as $newsEntry) { foreach ($news as $newsEntry) {
/** @var News $newsEntry */ /** @var News $newsEntry */
$categoryId = $newsEntry->getPid(); $newsCategory = $this->categoryRepository->findOriginalLanguageById(
$category = $categoriesById[$categoryId]; $newsEntry->getPid()
if (!$category) { ) ?? $this->categoryRepository->findByUid($newsEntry->getPid());
// Category isn't visible. $newsCategoryId = $newsCategory->getUid();
continue; $newsMetaData = $this->newsService->getMetaDataForNews($newsEntry, $newsCategory);
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;
}
}
} }
$data = $this->getMetaDataForNews($newsEntry, $category); $allNews[] = $newsMetaData;
$allNews[] = $data;
} }
$this->highlightBestFitNews($categoryIds); $this->highlightBestFitNews($categoryIds, $tagIds);
// Check to achieve less Ajax calls.
$newsCount = $this->newsRepository->newsCountByCategories($categoryIds, $tagIds, $startTime, $endTime); $newsCount = $this->newsRepository->newsCountByCategories($categoryIds, $tagIds, $startTime, $endTime);
$numberOfPages = (int) ($newsLimitPerCategory <= 0 ? 0 : ceil($newsCount / $newsLimitPerCategory)); $numberOfPages = (int) ($newsLimit <= 0 ? 0 : ceil($newsCount / $newsLimit));
if ($numberOfPages !== 0 && $currentPageBrowserPage >= $numberOfPages) { if ($numberOfPages !== 0 && $currentPageBrowserPage >= $numberOfPages) {
/** @var ErrorController $errorController */ /** @var ErrorController $errorController */
$errorController = GeneralUtility::makeInstance(ErrorController::class); $errorController = GeneralUtility::makeInstance(ErrorController::class);
...@@ -397,214 +288,94 @@ class OverviewController extends AbstractController { ...@@ -397,214 +288,94 @@ class OverviewController extends AbstractController {
throw new ImmediateResponseException($response); throw new ImmediateResponseException($response);
} }
// 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 // remember selection of the filter values, if any
$selectedTag = NULL; $selectedTag = $this->tagRepository->findByUid((int) $newsFilter['tag']);
if (isset($newsFilter['tag'])) { $selectedCategory = $this->categoryRepository->findByUid((int) $newsFilter['category']);
$selectedTag = $this->tagRepository->findByUid((int) $newsFilter['tag']);
}
$selectedCategory = NULL;
if(isset($newsFilter['category'])) {
$selectedCategory = $this->categoryRepository->findByUid((int) $newsFilter['category']);
}
$this->view->assign('selectedCategory', $selectedCategory); $this->view->assign('selectedCategory', $selectedCategory);
$this->view->assign('selectedTag', $selectedTag); $this->view->assign('selectedTag', $selectedTag);
$this->view->assign('tags', $tags); $this->view->assign('tags', $tags);
$this->view->assign('categories', $categories); $this->view->assign('categories', $categories);
$this->view->assign('numberOfPages', $numberOfPages); $this->view->assign('numberOfPages', $numberOfPages);
$this->view->assign('newsItems', $newsByCategory); $this->view->assign('newsItems', $newsItems);
$this->view->assign('groupBy', 'category');
$this->view->assign('allNews', $allNews); $this->view->assign('allNews', $allNews);
$this->view->assign('categoryTabs', TRUE); $this->setupGridColumns();
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');
}
} }
/** /**
* Renders the news overview grouped by tags * Assign the grid column classes to the frontend
* *
* @param array $newsByTag
* @param array $allNews
* @param array $newsFilter
* @param int $currentPageBrowserPage
* @return void * @return void
* @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( protected function setupGridColumns(): void {
array $newsByTag = [], if (!isset($this->settings['gridColumns'])) {
array $allNews = [], $this->view->assign('gridColumnClasses', 'col-md-4 col-sm-6 col-xs-12');
array $newsFilter = [], return;
int $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); $columnAmount = (int) $this->settings['gridColumns'];
$sortBy = $configurationService->getConfiguration('sortBy', $this->settings); $columnClasses = '';
$sortDirection = $configurationService->getConfiguration('sortDirection', $this->settings);
$categoryIds = NULL; switch ($columnAmount) {
if ($newsFilter['category']) { case 4:
$categoryIds = [(int) $newsFilter['category']]; $columnClasses .= 'col-lg-3 ';
} case 3:
$columnClasses .= 'col-md-4 ';
$this->tagRepository->setDefaultOrderings(['sorting' => QueryInterface::ORDER_ASCENDING]); case 2:
if ($this->settings['onlyNewsWithinThisPageSection']) { $columnClasses .= 'col-sm-6 ';
$tags = $this->tagRepository->findTagsInRootLine($tagPid); default:
} else { $columnClasses .= 'col-xs-12';
$tags = $this->tagRepository->findAll()->toArray();
} }
$tagRestrictions = GeneralUtility::intExplode(',', $this->settings['tagRestrictions'], TRUE); $this->view->assign('gridColumnClasses', $columnClasses);
if (count($tagRestrictions) > 0) { }
foreach ($tags as $key => $tag) {
if (!in_array($tag->getUid(), $tagRestrictions, TRUE)) {
unset($tags[$key]);
}
}
}
// Get news by tag id /**
$tagIds = []; * Highlights the best fitting news in the metadata of the page
$tagsById = []; *
$categoriesById = []; * @param array|null $categoryIds
$newsMetaData = []; * @param array|null $tagIds
foreach ($tags as $tag) { * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
/** @var Tag $tag */ */
$tagId = $tag->getUid(); protected function highlightBestFitNews(array $categoryIds = NULL, array $tagIds = NULL) {
$tagIds[] = $tagId; $startTime = (int) $this->settings['starttime'];
$tagsById[$tagId] = $tag; $endTime = (int) $this->settings['endtime'];
$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); /** @var News $highlightedNews */
} $highlightedNews = $this->newsRepository
->findLastUpdatedOrHighlightedNewsByCategories(
1, FALSE, $categoryIds, 0, FALSE, $this->settings['sortBy'], $tagIds, $startTime, $endTime
)->getFirst();
if (!$highlightedNews) {
return;
} }
// Process news by tag id /** @var Category $category */
$maxNewsPerTag = 0; $category = $this->categoryRepository->findByUid($highlightedNews->getPid());
foreach ($tagsById as $tagId => $tag) { $highlightedNewsMetaData = NULL;
if (\count($newsMetaData[$tagId]) <= 0) { if ($category) {
// Hide empty tags. $highlightedNewsMetaData = $this->newsService->getMetaDataForNews($highlightedNews, $category);
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. if (!version_compare(ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) {
if ($newsFilter['tag']) { if ($highlightedNewsMetaData['image']) {
$tagIds = [(int) $newsFilter['tag']]; HeaderMetaDataService::addOgImageToHeader($highlightedNewsMetaData['image']);
} } elseif ($highlightedNewsMetaData['teaserImage']) {
$news = $this->newsRepository->findAllSortedNewsByCategories( HeaderMetaDataService::addOgImageToHeader($highlightedNewsMetaData['teaserImage']);
$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);
}
/** @var Category $category */
$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 = (int) ($newsLimitPerTag <= 0 ? 0 : ceil($newsCount / $newsLimitPerTag));
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);
}
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
$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', $newsByTag);
$this->view->assign('groupBy', 'tag');
$this->view->assign('allNews', $allNews);
$this->view->assign('tagTabs', TRUE);
} }
/** /**
...@@ -625,17 +396,15 @@ class OverviewController extends AbstractController { ...@@ -625,17 +396,15 @@ class OverviewController extends AbstractController {
* @param array $newsMetaData * @param array $newsMetaData
* @param array|null $newsFilter * @param array|null $newsFilter
* @param int $currentPageBrowserPage * @param int $currentPageBrowserPage
* @return null|\Psr\Http\Message\ResponseInterface * @return void
* @throws ImmediateResponseException * @throws ImmediateResponseException
* @throws \TYPO3\CMS\Core\Error\Http\PageNotFoundException * @throws \TYPO3\CMS\Core\Error\Http\PageNotFoundException
* @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException * @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
*/ */
protected function overviewWithoutCategoriesAction( protected function overviewWithoutCategoriesAction(
array $newsMetaData = [], array $newsMetaData = [], array $newsFilter = NULL, int $currentPageBrowserPage = 0
array $newsFilter = NULL, ) {
int $currentPageBrowserPage = 0
): ?\Psr\Http\Message\ResponseInterface {
// remember selection of the filter values, if any // remember selection of the filter values, if any
$selectedTag = $this->tagRepository->findByUid((int) $newsFilter['tag']); $selectedTag = $this->tagRepository->findByUid((int) $newsFilter['tag']);
$selectedCategory = $this->categoryRepository->findByUid((int) $newsFilter['category']); $selectedCategory = $this->categoryRepository->findByUid((int) $newsFilter['category']);
...@@ -696,13 +465,7 @@ class OverviewController extends AbstractController { ...@@ -696,13 +465,7 @@ class OverviewController extends AbstractController {
} }
if ($newsCount <= 0) { if ($newsCount <= 0) {
if (version_compare( return;
\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<'
)) {
return NULL;
} else {
return $this->htmlResponse();
}
} }
// filter by category and tag if selected in the filter // filter by category and tag if selected in the filter
...@@ -716,18 +479,11 @@ class OverviewController extends AbstractController { ...@@ -716,18 +479,11 @@ class OverviewController extends AbstractController {
} }
$news = $this->newsRepository->findAllSortedNewsByCategories( $news = $this->newsRepository->findAllSortedNewsByCategories(
$categoryIds, $categoryIds, $newsPerPage, $offset, $sortBy, $tagIds, $startTime, $endTime, $sortDirection
$newsPerPage,
$offset,
$sortBy,
$tagIds,
$startTime,
$endTime,
$sortDirection
); );
foreach ($news as $newsEntry) { foreach ($news as $newsEntry) {
/** @var News $newsEntry */ /** @var News $newsEntry */
$data = $this->getMetaDataForNews($newsEntry, $categoriesById[$newsEntry->getPid()]); $data = $this->newsService->getMetaDataForNews($newsEntry, $categoriesById[$newsEntry->getPid()]);
$newsMetaData[] = $data; $newsMetaData[] = $data;
} }
...@@ -756,11 +512,7 @@ class OverviewController extends AbstractController { ...@@ -756,11 +512,7 @@ class OverviewController extends AbstractController {
$this->view->assign('categories', $categories); $this->view->assign('categories', $categories);
$this->view->assign('numberOfPages', $numberOfPages); $this->view->assign('numberOfPages', $numberOfPages);
$this->view->assign('newsMetaData', $newsMetaData); $this->view->assign('newsMetaData', $newsMetaData);
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) { $this->setupGridColumns();
return NULL;
} else {
return $this->htmlResponse();
}
} }
/** /**
......
...@@ -31,6 +31,7 @@ use SGalinski\SgNews\Domain\Model\News; ...@@ -31,6 +31,7 @@ use SGalinski\SgNews\Domain\Model\News;
use SGalinski\SgNews\Domain\Repository\CategoryRepository; use SGalinski\SgNews\Domain\Repository\CategoryRepository;
use SGalinski\SgNews\Domain\Repository\NewsRepository; use SGalinski\SgNews\Domain\Repository\NewsRepository;
use SGalinski\SgNews\Domain\Repository\TagRepository; use SGalinski\SgNews\Domain\Repository\TagRepository;
use SGalinski\SgNews\Domain\Service\NewsService;
use SGalinski\SgNews\Service\HeaderMetaDataService; use SGalinski\SgNews\Service\HeaderMetaDataService;
use TYPO3\CMS\Core\Charset\CharsetConverter; use TYPO3\CMS\Core\Charset\CharsetConverter;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
...@@ -59,6 +60,11 @@ class SingleViewController extends AbstractController { ...@@ -59,6 +60,11 @@ class SingleViewController extends AbstractController {
*/ */
protected $characterSetConverter; protected $characterSetConverter;
/**
* @var NewsService
*/
protected $newsService;
/** /**
* Renders the news single view * Renders the news single view
* *
...@@ -91,7 +97,7 @@ class SingleViewController extends AbstractController { ...@@ -91,7 +97,7 @@ class SingleViewController extends AbstractController {
} }
} }
$newsMetaData = $this->getMetaDataForNews($news, $newsCategory); $newsMetaData = $this->newsService->getMetaDataForNews($news, $newsCategory);
if (!version_compare(ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) { if (!version_compare(ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) {
if (isset($newsMetaData['imageObject'])) { if (isset($newsMetaData['imageObject'])) {
HeaderMetaDataService::addOgImageObjectToHeader( HeaderMetaDataService::addOgImageObjectToHeader(
...@@ -158,4 +164,11 @@ class SingleViewController extends AbstractController { ...@@ -158,4 +164,11 @@ class SingleViewController extends AbstractController {
public function injectTagRepository(TagRepository $tagRepository) { public function injectTagRepository(TagRepository $tagRepository) {
$this->tagRepository = $tagRepository; $this->tagRepository = $tagRepository;
} }
/**
* @param NewsService $newsService
*/
public function injectNewsService(NewsService $newsService) {
$this->newsService = $newsService;
}
} }
...@@ -97,14 +97,19 @@ class News extends CategoryAndNews { ...@@ -97,14 +97,19 @@ class News extends CategoryAndNews {
*/ */
protected $contentFromAnotherPage = 0; protected $contentFromAnotherPage = 0;
/**
* @var bool
*/
protected $enableComments = TRUE;
/** /**
* Constructor * Constructor
*/ */
public function __construct() { public function __construct() {
parent::__construct(); parent::__construct();
$this->relatedNews = new ObjectStorage();
$this->tags = new ObjectStorage(); $this->tags = new ObjectStorage();
$this->newsAuthor = new ObjectStorage(); $this->newsAuthor = new ObjectStorage();
$this->relatedNews = new ObjectStorage();
} }
/** /**
...@@ -383,4 +388,18 @@ class News extends CategoryAndNews { ...@@ -383,4 +388,18 @@ class News extends CategoryAndNews {
public function setContentFromAnotherPage(int $contentFromAnotherPage): void { public function setContentFromAnotherPage(int $contentFromAnotherPage): void {
$this->contentFromAnotherPage = $contentFromAnotherPage; $this->contentFromAnotherPage = $contentFromAnotherPage;
} }
/**
* @return bool
*/
public function getEnableComments(): bool {
return $this->enableComments;
}
/**
* @param bool $enableComments
*/
public function setEnableComments(bool $enableComments): void {
$this->enableComments = $enableComments;
}
} }
...@@ -26,8 +26,10 @@ namespace SGalinski\SgNews\Domain\Repository; ...@@ -26,8 +26,10 @@ namespace SGalinski\SgNews\Domain\Repository;
* This copyright notice MUST APPEAR in all copies of the script! * This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/ ***************************************************************/
use SGalinski\SgNews\Domain\Model\Author;
use SGalinski\SgNews\Domain\Model\News; use SGalinski\SgNews\Domain\Model\News;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Persistence\Generic\QueryResult; use TYPO3\CMS\Extbase\Persistence\Generic\QueryResult;
use TYPO3\CMS\Extbase\Persistence\QueryInterface; use TYPO3\CMS\Extbase\Persistence\QueryInterface;
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface; use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
...@@ -533,4 +535,102 @@ class NewsRepository extends AbstractRepository { ...@@ -533,4 +535,102 @@ class NewsRepository extends AbstractRepository {
$query->matching($query->equals('uid', $uid)); $query->matching($query->equals('uid', $uid));
return $query->execute()->getFirst(); return $query->execute()->getFirst();
} }
/**
* This method finds news related by Tag or Category to the given news record
*
* @param News $news The news to find related news to
* @param int $limit Limit the amount of related news
* @return QueryResultInterface
* @throws \Doctrine\DBAL\Driver\Exception
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
*/
public function findRelated(News $news, int $limit = 0): QueryResultInterface {
$connection = $this->getConnection();
$qb = $connection->createQueryBuilder();
// We need to build the constraint for the tags/categories
$constraints = [];
$tags = $news->getTags();
if ($tags->count() > 0) {
$qb->leftJoin('pages', 'sys_category_record_mm', 'tags', 'pages.uid=tags.uid_foreign');
$tagConstraints = [];
foreach ($tags as $tag) {
$tagConstraints[] = $qb->expr()->eq('tags.uid_local', $tag->getUid());
}
$constraints[] = $qb->expr()->eq('tags.tablenames', $qb->createNamedParameter('pages'));
$constraints[] = $qb->expr()->eq('tags.fieldname', $qb->createNamedParameter('tx_sgnews_tags'));
$constraints[] = $qb->expr()->orX(...$tagConstraints);
} else {
$constraints[] = $qb->expr()->eq('pid', $news->getPid());
}
if ($limit > 0) {
$qb->setMaxResults($limit);
}
// here we fetch the lastUpdated of the $limit amount of news with newer lastUpdated dates
$result = $qb->select('lastUpdated')
->from('pages', 'pages')
->where(
$qb->expr()->eq('doktype', $qb->createNamedParameter(News::DOK_TYPE_NEWS, Connection::PARAM_INT)),
$qb->expr()->gte('lastUpdated', $news->getLastUpdated()->getTimestamp())
)->andWhere(...$constraints)
->orderBy('lastUpdated', 'desc')
->execute();
$newest = $result->fetchOne();
// Here we fetch the lastUpdated of the $limit amount of news with older lastUpdated dates
$result = $qb->where(
$qb->expr()->eq('doktype', $qb->createNamedParameter(News::DOK_TYPE_NEWS, Connection::PARAM_INT)),
$qb->expr()->lte('lastUpdated', $news->getLastUpdated()->getTimestamp())
)->andWhere(...$constraints)
->orderBy('lastUpdated', 'asc')
->execute();
$oldest = $result->fetchOne();
$query = $this->createQuery();
$query->getQuerySettings()->setRespectStoragePage(FALSE);
$query->setOrderings([
'lastUpdated' => QueryInterface::ORDER_DESCENDING
]);
$constraints = [
$query->logicalNot(
$query->equals('uid', $news->getUid())
)
];
if ($newest) {
$constraints[] = $query->lessThanOrEqual('lastUpdated', $newest);
}
if ($oldest) {
$constraints[] = $query->greaterThanOrEqual('lastUpdated', $oldest);
}
// Now we fetch the $limit amount of news via extbase query and limit them to the newest and oldest date
// remember, we fetched the oldest and newest date from the $limit amount of news newer and older then
// the given news. If we limit the result of the following query to $limit, we get $limit amount of news
// "around" the given news, where newer news are preferred due to the ordering.
$tags = $news->getTags();
if ($tags->count() > 0) {
$tagConstraints = [];
foreach ($tags as $tag) {
$tagConstraints[] = $query->contains('tags', $tag);
}
$constraints[] = $query->logicalOr($tagConstraints);
} else {
$constraints[] = $query->equals('pid', $news->getPid());
}
$query->matching($query->logicalAnd($constraints));
if ($limit > 0) {
$query->setLimit($limit);
}
return $query->execute();
}
protected function getConnection(): Connection {
return GeneralUtility::makeInstance(ConnectionPool::class)
->getConnectionForTable('pages');
}
} }
<?php
namespace SGalinski\SgNews\Domain\Service;
/***************************************************************
* 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 TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Core\Resource\FileRepository;
/**
* This service takes care of meta data generation for the news objects
*/
class NewsService implements SingletonInterface {
/**
* @var array
*/
protected $cachedSingleNews = [];
/**
* Returns the metadata of the given news.
*
* @param News $news
* @param Category $category
* @return array
* @throws \InvalidArgumentException
*/
public function getMetaDataForNews(News $news, Category $category): array {
$newsId = $news->getUid();
if (isset($this->cachedSingleNews[$newsId])) {
return $this->cachedSingleNews[$newsId];
}
$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
$fileObjects = $fileRepository->findByRelation('pages', 'media', $news->getUid());
$singleNewsImageData = $this->getDataForSingleViewImage($news, $category);
$teaserImageData = $this->getDataForTeaserImage($news, $category);
// Use single news image data for teaser image data, if the teaser imaga data are empty.
$teaserIsEmpty = $teaserImageData['teaserImage'] === NULL && $teaserImageData['teaserImageObject'] === NULL;
$singleNewsIsEmpty = $singleNewsImageData['image'] === NULL && $singleNewsImageData['imageObject'] === NULL;
if ($teaserIsEmpty && !$singleNewsIsEmpty) {
$teaserImageData = [
'teaserImage' => $singleNewsImageData['image'],
'teaserImageObject' => $singleNewsImageData['imageObject'],
];
}
$newsRecord = array_merge(
[
'category' => $category,
'news' => $news,
],
$singleNewsImageData,
$teaserImageData,
['media' => $fileObjects]
);
$this->cachedSingleNews[$newsId] = $newsRecord;
return $newsRecord;
}
/**
* Returns the single view image data as an array for the given news and category as fallback.
*
* @param News $news
* @param Category $category
* @return array
* @throws \InvalidArgumentException
*/
public function getDataForSingleViewImage(News $news, Category $category): array {
/** @var FileReference $singleNewsImage */
$singleNewsImage = $singleNewsImageObject = NULL;
$singleNewsImages = $news->getTeaser2Image();
if (count($singleNewsImages)) {
$singleNewsImage = $singleNewsImages->current();
} else {
$categoryImages = $category->getTeaser2Image();
if (count($categoryImages)) {
$singleNewsImage = $categoryImages->current();
}
}
if ($singleNewsImage) {
$singleNewsImageObject = $singleNewsImage;
$originalResource = $singleNewsImage->getOriginalResource();
if ($originalResource) {
$singleNewsImage = $originalResource->getPublicUrl();
}
if ($singleNewsImage) {
$singleNewsImage = $GLOBALS['TSFE']->absRefPrefix . $singleNewsImage;
}
}
return [
'image' => $singleNewsImage,
'imageObject' => $singleNewsImageObject,
];
}
/**
* Returns the teaser image data as an array for the given news and category as fallback.
*
* @param News $news
* @param Category $category
* @return array
* @throws \InvalidArgumentException
*/
public function getDataForTeaserImage(News $news, Category $category): array {
/** @var FileReference $teaserImage */
$teaserImage = $teaserImageObject = NULL;
$teaserImages = $news->getTeaser1Image();
if (count($teaserImages)) {
$teaserImage = $teaserImages->current();
} else {
$categoryImages = $category->getTeaser1Image();
if (count($categoryImages)) {
$teaserImage = $categoryImages->current();
}
}
if ($teaserImage) {
$teaserImageObject = $teaserImage;
$originalResource = $teaserImage->getOriginalResource();
if ($originalResource) {
$teaserImage = $originalResource->getPublicUrl();
}
if ($teaserImage) {
$teaserImage = $GLOBALS['TSFE']->absRefPrefix . $teaserImage;
}
}
return [
'teaserImage' => $teaserImage,
'teaserImageObject' => $teaserImageObject,
];
}
}
<?php
namespace SGalinski\SgNews\ViewHelpers;
use SGalinski\SgNews\Domain\Repository\CategoryRepository;
use SGalinski\SgNews\Domain\Repository\NewsRepository;
use SGalinski\SgNews\Domain\Service\NewsService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
/**
* Renders related news based on the current news
*/
class RelatedViewHelper extends AbstractViewHelper {
use CompileWithRenderStatic;
/**
* @var bool
*/
protected $escapeOutput = false;
/**
* Initialize the view helper arguments
*/
public function initializeArguments() {
$this->registerArgument(
'news',
'SGalinski\SgNews\Domain\Model\News',
'The news record from which to find related news',
TRUE
);
$this->registerArgument(
'limit',
'int',
'Limit the amount of related news to display',
FALSE,
5
);
$this->registerArgument(
'as',
'string',
'The name of the iteration variable',
TRUE
);
$this->registerArgument(
'iteration', 'string',
'The name of the variable to store iteration information (index, cycle, isFirst, isLast, isEven, isOdd)'
);
$this->registerArgument(
'relatedNews',
ObjectStorage::class,
'An optional list of related news to take instead of finding some via the news repository',
FALSE,
NULL
);
}
/**
* It works like the for-ViewHelper by running through the child content and adding the related news records to it
*
* @param array $arguments
* @param \Closure $renderChildrenClosure
* @param RenderingContextInterface $renderingContext
* @return string
* @throws \Doctrine\DBAL\Driver\Exception
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
*/
public static function renderStatic(
array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext
) {
$newsService = GeneralUtility::makeInstance(NewsService::class);
$categoryRepository = GeneralUtility::makeInstance(CategoryRepository::class);
$templateVariableContainer = $renderingContext->getVariableProvider();
$news = $arguments['news'];
$newsRepository = GeneralUtility::makeInstance(NewsRepository::class);
if ($arguments['relatedNews']) {
$related = $arguments['relatedNews'];
} else {
$related = $newsRepository->findRelated($news, (int) $arguments['limit']);
}
if (isset($arguments['iteration'])) {
$iterationData = [
'index' => 0,
'cycle' => 1,
'total' => $related->count()
];
}
$output = '';
$categories = [];
foreach ($related as $relatedNews) {
if (!isset($categories[$relatedNews->getPid()])) {
$categories[$relatedNews->getPid()] = $categoryRepository->findByUid($relatedNews->getPid());
}
$newsMetaData = $newsService->getMetaDataForNews($relatedNews, $categories[$relatedNews->getPid()]);
$templateVariableContainer->add($arguments['as'], $newsMetaData);
if (isset($iterationData)) {
$iterationData['isFirst'] = $iterationData['cycle'] === 1;
$iterationData['isLast'] = $iterationData['cycle'] === $iterationData['total'];
$iterationData['isEven'] = $iterationData['cycle'] % 2 === 0;
$iterationData['isOdd'] = !$iterationData['isEven'];
$templateVariableContainer->add($arguments['iteration'], $iterationData);
$iterationData['index']++;
$iterationData['cycle']++;
}
$output .= $renderChildrenClosure();
$templateVariableContainer->remove($arguments['as']);
if (isset($arguments['iteration'])) {
$templateVariableContainer->remove($arguments['iteration']);
}
}
return $output;
}
}
...@@ -47,6 +47,9 @@ return [ ...@@ -47,6 +47,9 @@ return [
], ],
'dateEnd' => [ 'dateEnd' => [
'fieldName' => 'tx_sgnews_date_end' 'fieldName' => 'tx_sgnews_date_end'
],
'enableComments' => [
'fieldName' => 'tx_sgnews_comments_enable'
] ]
] ]
], ],
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
<settings.groupBy> <settings.groupBy>
<TCEforms> <TCEforms>
<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.groupBy</label> <label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.groupBy</label>
<description>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.groupBy.description</description>
<onChange>reload</onChange> <onChange>reload</onChange>
<config> <config>
<type>select</type> <type>select</type>
...@@ -36,11 +37,28 @@ ...@@ -36,11 +37,28 @@
</TCEforms> </TCEforms>
</settings.groupBy> </settings.groupBy>
<settings.enableFilter>
<TCEforms>
<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.enableFilter</label>
<description>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.enableFilter.description</description>
<onChange>reload</onChange>
<config>
<type>check</type>
<default>0</default>
</config>
</TCEforms>
</settings.enableFilter>
<settings.categoryRestrictions> <settings.categoryRestrictions>
<TCEforms> <TCEforms>
<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.categoryRestrictions</label> <label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.categoryRestrictions</label>
<description>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.categoryRestrictions.description</description> <description>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.categoryRestrictions.description</description>
<displayCond>FIELD:settings.groupBy:=:1</displayCond> <displayCond>
<or>
<value1>FIELD:settings.groupBy:=:1</value1>
<value2>FIELD:settings.enableFilter:=:1</value2>
</or>
</displayCond>
<config> <config>
<type>select</type> <type>select</type>
<renderType>selectMultipleSideBySide</renderType> <renderType>selectMultipleSideBySide</renderType>
...@@ -57,7 +75,12 @@ ...@@ -57,7 +75,12 @@
<TCEforms> <TCEforms>
<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.tags</label> <label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.tags</label>
<description>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.tags.description</description> <description>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.tags.description</description>
<displayCond>FIELD:settings.groupBy:=:2</displayCond> <displayCond>
<or>
<value1>FIELD:settings.groupBy:=:2</value1>
<value2>FIELD:settings.enableFilter:=:1</value2>
</or>
</displayCond>
<config> <config>
<type>select</type> <type>select</type>
<renderType>selectTree</renderType> <renderType>selectTree</renderType>
...@@ -77,16 +100,6 @@ ...@@ -77,16 +100,6 @@
</TCEforms> </TCEforms>
</settings.tagRestrictions> </settings.tagRestrictions>
<settings.enableFilter>
<TCEforms>
<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.enableFilter</label>
<description>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.enableFilter.description</description>
<config>
<type>check</type>
<default>0</default>
</config>
</TCEforms>
</settings.enableFilter>
<settings.categoryLabel> <settings.categoryLabel>
<TCEforms> <TCEforms>
<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.categoryLabel</label> <label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.categoryLabel</label>
...@@ -98,11 +111,20 @@ ...@@ -98,11 +111,20 @@
<settings.tagLabel> <settings.tagLabel>
<TCEforms> <TCEforms>
<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.tagLabel</label> <label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.tagLabel</label>
<description>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.tagLabel.description</description>
<config> <config>
<type>input</type> <type>input</type>
</config> </config>
</TCEforms> </TCEforms>
</settings.tagLabel> </settings.tagLabel>
<settings.allLabel>
<TCEforms>
<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.allLabel</label>
<config>
<type>input</type>
</config>
</TCEforms>
</settings.allLabel>
<settings.newsLimit> <settings.newsLimit>
<TCEforms> <TCEforms>
<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.newsLimit</label> <label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.newsLimit</label>
...@@ -192,6 +214,53 @@ ...@@ -192,6 +214,53 @@
</config> </config>
</TCEforms> </TCEforms>
</settings.sortDirection> </settings.sortDirection>
<settings.layout>
<TCEforms>
<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.layout</label>
<config>
<type>select</type>
<renderType>selectSingle</renderType>
<items>
<numIndex index="0">
<numIndex index="0">LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.layout.1</numIndex>
<numIndex index="1">1</numIndex>
</numIndex>
<numIndex index="1">
<numIndex index="0">LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.layout.2</numIndex>
<numIndex index="1">2</numIndex>
</numIndex>
</items>
</config>
</TCEforms>
</settings.layout>
<settings.gridColumns>
<TCEforms>
<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.gridColumns</label>
<config>
<type>select</type>
<renderType>selectSingle</renderType>
<default>3</default>
<items>
<numIndex index="0">
<numIndex index="0">LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.gridColumns.1</numIndex>
<numIndex index="1">1</numIndex>
</numIndex>
<numIndex index="1">
<numIndex index="0">LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.gridColumns.2</numIndex>
<numIndex index="1">2</numIndex>
</numIndex>
<numIndex index="2">
<numIndex index="0">LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.gridColumns.3</numIndex>
<numIndex index="1">3</numIndex>
</numIndex>
<numIndex index="3">
<numIndex index="0">LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.gridColumns.4</numIndex>
<numIndex index="1">4</numIndex>
</numIndex>
</items>
</config>
</TCEforms>
</settings.gridColumns>
</el> </el>
</ROOT> </ROOT>
</main> </main>
......
...@@ -449,6 +449,14 @@ if (version_compare(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExten ...@@ -449,6 +449,14 @@ if (version_compare(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExten
'allowLanguageSynchronization' => TRUE 'allowLanguageSynchronization' => TRUE
] ]
] ]
],
'tx_sgnews_comments_enable' => [
'exclude' => TRUE,
'label' => $localLangDbPath . 'pages.tx_sgnews_comments_enable',
'config' => [
'type' => 'check',
'default' => 1
]
] ]
] ]
); );
...@@ -460,7 +468,8 @@ $GLOBALS['TCA']['pages']['palettes']['titleDescriptionAndHighlightFlag'] = [ ...@@ -460,7 +468,8 @@ $GLOBALS['TCA']['pages']['palettes']['titleDescriptionAndHighlightFlag'] = [
--linebreak--, slug, --linebreak--, slug,
--linebreak--, tx_projectbase_path_segment, tx_projectbase_excludefromsluggeneration, --linebreak--, tx_projectbase_path_segment, tx_projectbase_excludefromsluggeneration,
--linebreak--, tx_realurl_pathsegment, tx_realurl_exclude, --linebreak--, tx_realurl_pathsegment, tx_realurl_exclude,
--linebreak--, tx_sgnews_highlighted, tx_sgnews_never_highlighted', --linebreak--, tx_sgnews_highlighted, tx_sgnews_never_highlighted,
--linebreak--, tx_sgnews_comments_enable',
'canNotCollapse' => 1, 'canNotCollapse' => 1,
]; ];
...@@ -496,6 +505,7 @@ foreach ($GLOBALS['TCA']['pages']['columns'] as $languageExcludeField => $_) { ...@@ -496,6 +505,7 @@ foreach ($GLOBALS['TCA']['pages']['columns'] as $languageExcludeField => $_) {
'tx_sgnews_date_end', 'tx_sgnews_date_end',
'tx_sgnews_highlighted', 'tx_sgnews_highlighted',
'tx_sgnews_never_highlighted', 'tx_sgnews_never_highlighted',
'tx_sgnews_comments_enable',
'og_title', 'og_title',
'og_description', 'og_description',
'og_image', 'og_image',
...@@ -527,6 +537,7 @@ foreach ($GLOBALS['TCA']['pages']['columns'] as $languageExcludeField => $_) { ...@@ -527,6 +537,7 @@ foreach ($GLOBALS['TCA']['pages']['columns'] as $languageExcludeField => $_) {
'tx_sgnews_date_end', 'tx_sgnews_date_end',
'tx_sgnews_highlighted', 'tx_sgnews_highlighted',
'tx_sgnews_never_highlighted', 'tx_sgnews_never_highlighted',
'tx_sgnews_comments_enable'
]; ];
} }
if (!in_array($languageExcludeField, $fieldNames)) { if (!in_array($languageExcludeField, $fieldNames)) {
......
...@@ -19,5 +19,8 @@ plugin.tx_sgnews { ...@@ -19,5 +19,8 @@ plugin.tx_sgnews {
# sort direction (DESC / ASC) # sort direction (DESC / ASC)
sortDirection = DESC sortDirection = DESC
# This enables the output of related news in regards to the news category or tags
enableAutomaticRelatedNews = 0
} }
} }
...@@ -109,6 +109,9 @@ plugin.tx_sgnews { ...@@ -109,6 +109,9 @@ plugin.tx_sgnews {
# The logo value for the structured data implementation (see single view template) # The logo value for the structured data implementation (see single view template)
publisherLogo = publisherLogo =
# This enables the output of related news in regards to the news category or tags
enableAutomaticRelatedNews = {$plugin.tx_sgnews.settings.enableAutomaticRelatedNews}
} }
features { features {
......
...@@ -81,6 +81,10 @@ ...@@ -81,6 +81,10 @@
<source><![CDATA[Use Image Cropping]]></source> <source><![CDATA[Use Image Cropping]]></source>
<target><![CDATA[Bild-Cropping aktivieren]]></target> <target><![CDATA[Bild-Cropping aktivieren]]></target>
</trans-unit> </trans-unit>
<trans-unit id="pages.tx_sgnews_comments_enable" approved="yes">
<source><![CDATA[Enable comments on this page]]></source>
<target><![CDATA[Kommentare auf dieser Seite aktivieren]]></target>
</trans-unit>
<trans-unit id="plugin.flexForm" approved="yes"> <trans-unit id="plugin.flexForm" approved="yes">
<source><![CDATA[Settings]]></source> <source><![CDATA[Settings]]></source>
<target><![CDATA[Einstellungen]]></target> <target><![CDATA[Einstellungen]]></target>
...@@ -109,6 +113,26 @@ ...@@ -109,6 +113,26 @@
<source><![CDATA[News which are excluded from the list]]></source> <source><![CDATA[News which are excluded from the list]]></source>
<target><![CDATA[News, welche nicht in der Liste dargestellt werden]]></target> <target><![CDATA[News, welche nicht in der Liste dargestellt werden]]></target>
</trans-unit> </trans-unit>
<trans-unit id="plugin.flexForm.gridColumns" approved="yes">
<source><![CDATA[Columns]]></source>
<target><![CDATA[Anzahl der Spalten]]></target>
</trans-unit>
<trans-unit id="plugin.flexForm.gridColumns.1" approved="yes">
<source><![CDATA[1 Column]]></source>
<target><![CDATA[1 Spalte]]></target>
</trans-unit>
<trans-unit id="plugin.flexForm.gridColumns.2" approved="yes">
<source><![CDATA[2 Columns]]></source>
<target><![CDATA[2 Spalten]]></target>
</trans-unit>
<trans-unit id="plugin.flexForm.gridColumns.3" approved="yes">
<source><![CDATA[3 Columns]]></source>
<target><![CDATA[3 Spalten]]></target>
</trans-unit>
<trans-unit id="plugin.flexForm.gridColumns.4" approved="yes">
<source><![CDATA[4 Columns]]></source>
<target><![CDATA[4 Spalten]]></target>
</trans-unit>
<trans-unit id="plugin.flexForm.layout" approved="yes"> <trans-unit id="plugin.flexForm.layout" approved="yes">
<source><![CDATA[Layout]]></source> <source><![CDATA[Layout]]></source>
<target><![CDATA[Layout]]></target> <target><![CDATA[Layout]]></target>
...@@ -189,6 +213,14 @@ ...@@ -189,6 +213,14 @@
<source><![CDATA[Categories]]></source> <source><![CDATA[Categories]]></source>
<target><![CDATA[Kategorien]]></target> <target><![CDATA[Kategorien]]></target>
</trans-unit> </trans-unit>
<trans-unit id="plugin.overview.flexForm.allLabel" approved="yes">
<source><![CDATA[Override all label]]></source>
<target><![CDATA[Alle-Label überschreiben]]></target>
</trans-unit>
<trans-unit id="plugin.overview.flexForm.allLabel.description" approved="yes">
<source><![CDATA[Will be used when filtering by all criteria is disabled.]]></source>
<target><![CDATA[Wird nur bei nicht aktivierten Filtern von allen Kriterien verwendet.]]></target>
</trans-unit>
<trans-unit id="plugin.overview.flexForm.categoryLabel" approved="yes"> <trans-unit id="plugin.overview.flexForm.categoryLabel" approved="yes">
<source><![CDATA[Override category label]]></source> <source><![CDATA[Override category label]]></source>
<target><![CDATA[Kategorie-Label überschreiben]]></target> <target><![CDATA[Kategorie-Label überschreiben]]></target>
...@@ -220,16 +252,20 @@ If none are selected, all categories will be available in the frontend.]]></sour ...@@ -220,16 +252,20 @@ If none are selected, all categories will be available in the frontend.]]></sour
Wenn keine ausgewählt werden, sind alle Kategorien im Frontend verfügbar.]]></target> Wenn keine ausgewählt werden, sind alle Kategorien im Frontend verfügbar.]]></target>
</trans-unit> </trans-unit>
<trans-unit id="plugin.overview.flexForm.enableFilter" approved="yes"> <trans-unit id="plugin.overview.flexForm.enableFilter" approved="yes">
<source><![CDATA[Enable filtering by all criteria.]]></source> <source><![CDATA[Show all filters]]></source>
<target><![CDATA[Ermögliche das Filtern mit allen Krierien.]]></target> <target><![CDATA[Zeige alle Filter an]]></target>
</trans-unit> </trans-unit>
<trans-unit id="plugin.overview.flexForm.enableFilter.description" approved="yes"> <trans-unit id="plugin.overview.flexForm.enableFilter.description" approved="yes">
<source><![CDATA[Filters will be rendered as select boxes and tabs will be hidden.]]></source> <source><![CDATA[Filters will be rendered as select boxes and tabs will be hidden.]]></source>
<target><![CDATA[Filter werden als Dropdown-Box angezeigt und die Tabs ausgeblendet.]]></target> <target><![CDATA[Filter werden als Dropdown-Box angezeigt und die Tabs ausgeblendet.]]></target>
</trans-unit> </trans-unit>
<trans-unit id="plugin.overview.flexForm.groupBy" approved="yes"> <trans-unit id="plugin.overview.flexForm.groupBy" approved="yes">
<source><![CDATA[Group news pages in tabs by]]></source> <source><![CDATA[Group news pages by]]></source>
<target><![CDATA[News-Seiten nach folgendem Kriterium in Tabs gruppieren]]></target> <target><![CDATA[News-Seiten nach folgendem Kriterium gruppieren]]></target>
</trans-unit>
<trans-unit id="plugin.overview.flexForm.groupBy.description" approved="yes">
<source><![CDATA[News pages will be grouped in tabs.]]></source>
<target><![CDATA[News-Seiten werden in Tabs gruppiert.]]></target>
</trans-unit> </trans-unit>
<trans-unit id="plugin.overview.flexForm.groupBy.I.0" approved="yes"> <trans-unit id="plugin.overview.flexForm.groupBy.I.0" approved="yes">
<source><![CDATA[No grouping]]></source> <source><![CDATA[No grouping]]></source>
......
...@@ -63,6 +63,9 @@ ...@@ -63,6 +63,9 @@
<trans-unit id="pages.tx_sgnews_use_image_crop"> <trans-unit id="pages.tx_sgnews_use_image_crop">
<source><![CDATA[Use Image Cropping]]></source> <source><![CDATA[Use Image Cropping]]></source>
</trans-unit> </trans-unit>
<trans-unit id="pages.tx_sgnews_comments_enable">
<source><![CDATA[Enable comments on this page]]></source>
</trans-unit>
<trans-unit id="plugin.flexForm"> <trans-unit id="plugin.flexForm">
<source><![CDATA[Settings]]></source> <source><![CDATA[Settings]]></source>
</trans-unit> </trans-unit>
...@@ -84,6 +87,21 @@ ...@@ -84,6 +87,21 @@
<trans-unit id="plugin.flexForm.excludedNews"> <trans-unit id="plugin.flexForm.excludedNews">
<source><![CDATA[News which are excluded from the list]]></source> <source><![CDATA[News which are excluded from the list]]></source>
</trans-unit> </trans-unit>
<trans-unit id="plugin.flexForm.gridColumns">
<source><![CDATA[Columns]]></source>
</trans-unit>
<trans-unit id="plugin.flexForm.gridColumns.1">
<source><![CDATA[1 Column]]></source>
</trans-unit>
<trans-unit id="plugin.flexForm.gridColumns.2">
<source><![CDATA[2 Columns]]></source>
</trans-unit>
<trans-unit id="plugin.flexForm.gridColumns.3">
<source><![CDATA[3 Columns]]></source>
</trans-unit>
<trans-unit id="plugin.flexForm.gridColumns.4">
<source><![CDATA[4 Columns]]></source>
</trans-unit>
<trans-unit id="plugin.flexForm.layout"> <trans-unit id="plugin.flexForm.layout">
<source><![CDATA[Layout]]></source> <source><![CDATA[Layout]]></source>
</trans-unit> </trans-unit>
...@@ -156,6 +174,12 @@ ...@@ -156,6 +174,12 @@
<trans-unit id="plugin.overview.flexForm.categoryRestrictions"> <trans-unit id="plugin.overview.flexForm.categoryRestrictions">
<source><![CDATA[Category Selection]]></source> <source><![CDATA[Category Selection]]></source>
</trans-unit> </trans-unit>
<trans-unit id="plugin.overview.flexForm.allLabel">
<source><![CDATA[Override all label]]></source>
</trans-unit>
<trans-unit id="plugin.overview.flexForm.allLabel.description">
<source><![CDATA[Will be used when filtering by all criteria is disabled.]]></source>
</trans-unit>
<trans-unit id="plugin.overview.flexForm.categoryLabel"> <trans-unit id="plugin.overview.flexForm.categoryLabel">
<source><![CDATA[Override category label]]></source> <source><![CDATA[Override category label]]></source>
</trans-unit> </trans-unit>
...@@ -167,13 +191,16 @@ ...@@ -167,13 +191,16 @@
If none are selected, all categories will be available in the frontend.]]></source> If none are selected, all categories will be available in the frontend.]]></source>
</trans-unit> </trans-unit>
<trans-unit id="plugin.overview.flexForm.enableFilter"> <trans-unit id="plugin.overview.flexForm.enableFilter">
<source><![CDATA[Enable filtering by all criteria.]]></source> <source><![CDATA[Show all filters]]></source>
</trans-unit> </trans-unit>
<trans-unit id="plugin.overview.flexForm.enableFilter.description"> <trans-unit id="plugin.overview.flexForm.enableFilter.description">
<source><![CDATA[Filters will be rendered as select boxes and tabs will be hidden.]]></source> <source><![CDATA[Filters will be rendered as select boxes and tabs will be hidden.]]></source>
</trans-unit> </trans-unit>
<trans-unit id="plugin.overview.flexForm.groupBy"> <trans-unit id="plugin.overview.flexForm.groupBy">
<source><![CDATA[Group news pages in tabs by]]></source> <source><![CDATA[Group news pages by]]></source>
</trans-unit>
<trans-unit id="plugin.overview.flexForm.groupBy.description">
<source><![CDATA[News pages will be grouped in tabs.]]></source>
</trans-unit> </trans-unit>
<trans-unit id="plugin.overview.flexForm.groupBy.I.0"> <trans-unit id="plugin.overview.flexForm.groupBy.I.0">
<source><![CDATA[No grouping]]></source> <source><![CDATA[No grouping]]></source>
......
{namespace sg=SGalinski\SgNews\ViewHelpers}
<f:comment>
<!--
Usage Example:
<f:render partial="Teaser" arguments="{
newsMetaData: newsMetaData,
headerTag: '<h3>',
closingHeaderTag: '</h3>',
showCategory: 1
}" />
newsMetaData -> news element
headerTag -> hierarchy type of the header tag
showCategory -> defines if the category may be shown
Use <f:debug>{_all}</f:debug> to see all parameters and fields.
-->
</f:comment>
<f:link.page pageUid="{news.uid}" class="tx-sgnews-teaser">
<f:if condition="{news.teaser1Image}">
<f:for each="{news.teaser1Image}" as="teaserImage">
<div class="tx-sgnews-teaser-image tx-sgnews-teaser-image-stretched"
style="background-image: url({f:uri.image(image: teaserImage)});"></div>
</f:for>
</f:if>
<div class="tx-sgnews-teaser-inner">
<div class="tx-sgnews-teaser-title">
{headerTag -> f:format.raw()}
{news.subtitleWithFallbackToTitle}
{closingHeaderTag -> f:format.raw()}
</div>
</div>
</f:link.page>
...@@ -18,7 +18,14 @@ ...@@ -18,7 +18,14 @@
<div class="tx-sgnews-categories m-tabs" data-more-label="Mehr"> <div class="tx-sgnews-categories m-tabs" data-more-label="Mehr">
<div class="m-tabs__tablist" role="tablist"> <div class="m-tabs__tablist" role="tablist">
<button class="m-tabs__tab" role="tab" aria-controls="news-category-0" id="tab-news-0" aria-selected="true"> <button class="m-tabs__tab" role="tab" aria-controls="news-category-0" id="tab-news-0" aria-selected="true">
<f:translate key="frontend.overview.allTabLabel" /> <f:if condition="{settings.allLabel}">
<f:then>
{settings.allLabel}
</f:then>
<f:else>
<f:translate key="frontend.overview.allTabLabel" />
</f:else>
</f:if>
</button> </button>
<f:for each="{newsItems}" as="dataItems" iteration="iterator"> <f:for each="{newsItems}" as="dataItems" iteration="iterator">
<button class="m-tabs__tab" role="tab" aria-controls="news-category-{iterator.index + 1}" id="tab-news-{iterator.index + 1}" aria-selected="false"> <button class="m-tabs__tab" role="tab" aria-controls="news-category-{iterator.index + 1}" id="tab-news-{iterator.index + 1}" aria-selected="false">
...@@ -51,7 +58,7 @@ ...@@ -51,7 +58,7 @@
<ul class="tx-sgnews-list tx-sgnews-list-{dataItems.record.uid} row" data-record="{dataItems.record.uid}"> <ul class="tx-sgnews-list tx-sgnews-list-{dataItems.record.uid} row" data-record="{dataItems.record.uid}">
<f:for each="{dataItems.newsMetaData}" as="newsMetaDataEntry"> <f:for each="{dataItems.newsMetaData}" as="newsMetaDataEntry">
<f:if condition="{newsMetaDataEntry.news}"> <f:if condition="{newsMetaDataEntry.news}">
<li class="col-md-4 col-sm-6 col-xs-12"> <li class="{gridColumnClasses}">
<f:render partial="Teaser" arguments="{ <f:render partial="Teaser" arguments="{
newsMetaData: newsMetaDataEntry, newsMetaData: newsMetaDataEntry,
headerTag: '<h2>', headerTag: '<h2>',
...@@ -85,7 +92,7 @@ ...@@ -85,7 +92,7 @@
<f:section name="content"> <f:section name="content">
<ul class="tx-sgnews-list tx-sgnews-list-0 row" data-record="0"> <ul class="tx-sgnews-list tx-sgnews-list-0 row" data-record="0">
<f:for each="{allNews}" as="newsMetaDataEntry"> <f:for each="{allNews}" as="newsMetaDataEntry">
<li class="col-md-4 col-sm-6 col-xs-12"> <li class="{gridColumnClasses}">
<f:render partial="Teaser" arguments="{ <f:render partial="Teaser" arguments="{
newsMetaData: newsMetaDataEntry, newsMetaData: newsMetaDataEntry,
headerTag: '<h2>', headerTag: '<h2>',
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
<f:then> <f:then>
<ul class="tx-sgnews-list tx-sgnews-list-0 row" data-record="0"> <ul class="tx-sgnews-list tx-sgnews-list-0 row" data-record="0">
<f:for each="{newsMetaData}" as="newsMetaDataEntry"> <f:for each="{newsMetaData}" as="newsMetaDataEntry">
<li class="col-md-4 col-sm-6 col-xs-12"> <li class="{gridColumnClasses}">
<f:render partial="Teaser" arguments="{ <f:render partial="Teaser" arguments="{
newsMetaData: newsMetaDataEntry, newsMetaData: newsMetaDataEntry,
headerTag: '<h2>', headerTag: '<h2>',
......
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