Commit 625dd7c9 authored by Matthias Adrowski's avatar Matthias Adrowski
Browse files

Merge branch 'feature_Upgrade-to-TYPO3-11' into 'master'

Feature upgrade to typo3 11

See merge request !10
parents abc1c444 4eb9a247
......@@ -28,12 +28,9 @@ namespace SGalinski\DfTabs\Controller;
use SGalinski\DfTabs\DataProvider\AbstractBaseDataProvider;
use SGalinski\DfTabs\Domain\Repository\TabRepository;
use SGalinski\DfTabs\Service\ConfigurationService;
use SGalinski\DfTabs\View\TypoScriptView;
use SGalinski\DfTabs\View\FluidView;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
use TYPO3\CMS\Frontend\Plugin\AbstractPlugin;
/**
......@@ -70,14 +67,14 @@ class PluginController extends AbstractPlugin {
*
* @var AbstractBaseDataProvider
*/
protected $dataProvider = NULL;
protected $dataProvider;
/**
* Plugin configuration
*
* @var array
*/
protected $pluginConfiguration = array();
protected $pluginConfiguration = [];
/**
* Returns an instance of the renderer
......@@ -86,23 +83,8 @@ class PluginController extends AbstractPlugin {
* @return FluidView
*/
protected function getRenderer($tabId) {
/** @var TypoScriptFrontendController $tsfe */
$tsfe = $GLOBALS['TSFE'];
if ($this->pluginConfiguration['renderer'] === 'TypoScript' || !$this->pluginConfiguration['renderer']) {
/** @var $renderer TypoScriptView */
$renderer = GeneralUtility::makeInstance(TypoScriptView::class);
$renderer->injectPluginConfiguration($this->pluginConfiguration, $tabId);
$renderer->injectPageRenderer(GeneralUtility::makeInstance(PageRenderer::class));
$renderer->injectContentObject($this->cObj);
$repository = $this->getTabRepository();
$records = $repository->getRecords();
$renderer->addInlineJavaScriptCode($records, $this->pluginConfiguration['mode'], $tabId);
} else if ($this->pluginConfiguration['renderer'] === 'Fluid') {
/** @var $renderer FluidView */
$renderer = GeneralUtility::makeInstance(FluidView::class, $this->pluginConfiguration);
}
/** @var FluidView $renderer */
$renderer = GeneralUtility::makeInstance(FluidView::class, $this->pluginConfiguration);
return $renderer;
}
......@@ -112,7 +94,7 @@ class PluginController extends AbstractPlugin {
* @return ConfigurationService
*/
protected function getConfigurationManager() {
/** @var $configurationManager ConfigurationService */
/** @var ConfigurationService $configurationManager */
$configurationManager = GeneralUtility::makeInstance(ConfigurationService::class);
$configurationManager->injectControllerContext($this);
......@@ -125,7 +107,7 @@ class PluginController extends AbstractPlugin {
* @return TabRepository
*/
protected function getTabRepository() {
/** @var $repository TabRepository */
/** @var TabRepository $repository */
$repository = GeneralUtility::makeInstance(TabRepository::class);
$repository->injectContentObject($this->cObj);
$repository->injectPluginConfiguration($this->pluginConfiguration);
......@@ -158,14 +140,15 @@ class PluginController extends AbstractPlugin {
$records = $repository->getRecords();
$tabElements = $repository->buildTabElements($this->pluginConfiguration['titles'] ?? [], $records);
$content .= $renderer->renderTabs($tabElements, $tabId);
} catch (\Exception $exception) {
$content = $exception->getMessage();
}
$this->prefixId = $this->pluginConfiguration['classPrefix'] . 'plugin1';
if (isset($this->pluginConfiguration['classPrefix'])) {
$this->prefixId = $this->pluginConfiguration['classPrefix'] . 'plugin1';
} else {
$this->prefixId = 'plugin1';
}
return $this->pi_wrapInBaseClass($content);
}
}
?>
......@@ -52,7 +52,7 @@ abstract class AbstractBaseDataProvider implements InterfaceDataProvider, Single
* @param array $configuration
* @return void
*/
public function injectPluginConfiguration(array $configuration) {
public function addPluginConfiguration(array $configuration) {
$this->pluginConfiguration = $configuration;
}
......
......@@ -62,7 +62,7 @@ abstract class AbstractDataBaseDataProvider extends AbstractBaseDataProvider {
->from($this->table)
->where(
$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
)->execute()->fetch();
)->execute()->fetchAssociative();
/** @var TypoScriptFrontendController $typoscriptController */
$typoscriptController = $GLOBALS['TSFE'];
......@@ -75,7 +75,9 @@ abstract class AbstractDataBaseDataProvider extends AbstractBaseDataProvider {
) {
if ($this->table !== 'pages') {
$row = $typoscriptController->sys_page->getRecordOverlay(
$this->table, $row, $sysLanguageContent,
$this->table,
$row,
$sysLanguageContent,
$sysLanguageContentOl
);
} else {
......@@ -112,7 +114,7 @@ abstract class AbstractDataBaseDataProvider extends AbstractBaseDataProvider {
'dontCheckPid' => 1
];
if (\is_array($this->pluginConfiguration['records.'])) {
if (\array_key_exists('records.', $this->pluginConfiguration) && \is_array($this->pluginConfiguration['records.'])) {
$configuration = \array_merge($configuration, $this->pluginConfiguration['records.']);
}
......
......@@ -38,7 +38,7 @@ final class FactoryDataProvider {
* to instantiate the table instance with needed information's.
*
* @throws GenericException if no valid data provider could be created
* @param string $type pages, tt_content, typoscript, ...
* @param string $type pages, tt_content ...
* @param array $pluginConfiguration
* @param ContentObjectRenderer $contentObject
* @return AbstractBaseDataProvider
......@@ -49,14 +49,12 @@ final class FactoryDataProvider {
$dataProvider = GeneralUtility::makeInstance(ContentDataProvider::class);
} elseif ($type === 'pages') {
$dataProvider = GeneralUtility::makeInstance(PagesDataProvider::class);
} elseif ($type === 'typoscript') {
$dataProvider = GeneralUtility::makeInstance(TypoScriptDataProvider::class);
} else {
throw new GenericException('No data provider matched your request!');
}
/** @var $dataProvider AbstractBaseDataProvider */
$dataProvider->injectPluginConfiguration($pluginConfiguration);
$dataProvider->addPluginConfiguration($pluginConfiguration);
$dataProvider->injectContentObject($contentObject);
return $dataProvider;
......
......@@ -54,5 +54,3 @@ interface InterfaceDataProvider {
*/
public function getLinkData($uid);
}
?>
......@@ -67,7 +67,7 @@ class PagesDataProvider extends AbstractDataBaseDataProvider {
}
}
$contentElements = $queryBuilder->execute()->fetchAll();
$contentElements = $queryBuilder->execute()->fetchAllAssociative();
return \array_column($contentElements, 'uid');
}
}
......@@ -43,7 +43,7 @@ class TabRepository {
/**
* @var ContentObjectRenderer
*/
protected $contentObject = NULL;
protected $contentObject;
/**
* Injects an instance of the content object
......@@ -73,7 +73,9 @@ class TabRepository {
*/
protected function getDataProvider($type) {
return FactoryDataProvider::getDataProvider(
$type, $this->pluginConfiguration, $this->contentObject
$type,
$this->pluginConfiguration,
$this->contentObject
);
}
......@@ -153,7 +155,7 @@ class TabRepository {
));
}
/** @var $tabElement Tab */
/** @var Tab $tabElement */
$tabElement = GeneralUtility::makeInstance(Tab::class, htmlspecialchars($title), $recordId);
$tabElement->setLink($dataProvider->getLinkData($recordId));
$tabElement->setContent($dataProvider->getTabContent($recordId));
......
......@@ -20,6 +20,7 @@ namespace SGalinski\DfTabs\Hooks\PageLayoutView;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use SGalinski\DfTabs\Preview\PreviewService;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Backend\View\PageLayoutView;
use TYPO3\CMS\Core\Localization\LanguageService;
......@@ -32,75 +33,31 @@ use TYPO3\CMS\Fluid\View\StandaloneView;
* @package SGalinski\DfTabs\Hooks\PageLayoutView
*/
class PluginRenderer implements \TYPO3\CMS\Backend\View\PageLayoutViewDrawItemHookInterface {
protected PreviewService $previewService;
public function init() {
$this->previewService = GeneralUtility::makeInstance(PreviewService::class);
}
/**
* @inheritDoc
* @noinspection ReferencingObjectsInspection
*/
public function preProcess(
PageLayoutView &$parentObject, &$drawItem, &$headerContent, &$itemContent, array &$row
PageLayoutView &$parentObject,
&$drawItem,
&$headerContent,
&$itemContent,
array &$row
): void {
$this->init();
if ($row['list_type'] === 'df_tabs_plugin1') {
$drawItem = FALSE;
$view = GeneralUtility::makeInstance(StandaloneView::class);
$view->setPartialRootPaths(['EXT:df_tabs/Resources/Private/Partials/Backend']);
$view->setTemplateRootPaths(['EXT:df_tabs/Resources/Private/Templates/Backend']);
$view->setTemplate('Tabs.html');
$view->assign('uid', $row['uid']);
$this->adaptPluginHeaderContent($headerContent, $row);
// Get available plugin settings and their values from flexform
$pluginConfiguration = GeneralUtility::xml2array(
$row['pi_flexform'], 'T3DataStructure'
)['data']['sDEF']['lDEF'];
$tabElements = GeneralUtility::trimExplode(',',$pluginConfiguration['data']['vDEF'], TRUE);
$tabs = [];
foreach ($tabElements as $tabElement) {
// Each $tabElement is either 'pages_<id>' or 'tt_content_<id>'.
$recordTable = substr($tabElement, 0, strrpos($tabElement, '_'));
$recordId = substr($tabElement, strrpos($tabElement, '_') + 1);
if ($recordTable === 'pages'){
$recordTitle = BackendUtility::getRecord($recordTable, $recordId, 'title')['title'];
$recordType = 'page';
} elseif ($recordTable === 'tt_content') {
$recordTitle = BackendUtility::getRecord($recordTable, $recordId, 'header')['header'];
$recordType = 'content';
} else {
$recordTitle = $tabElement;
$recordType = 'unknown';
}
$tabs[] = [
'type' => $recordType,
'title' => $recordTitle,
'uid' => $recordId
];
}
$titles = GeneralUtility::trimExplode("\n",$pluginConfiguration['titles']['vDEF']);
// Remove first item if it is empty to mimic what is actually saved to the DB and frontend behaviour.
// This gets done automatically on a second save of the plugin anyways but it should happen every time.
if ($titles[0] === '') {
array_shift($titles);
}
$templateData = [
'mode' => $pluginConfiguration['mode']['vDEF'],
'tabs' => $tabs,
'titles' => $titles,
'enableAutoPlay' => $pluginConfiguration['enableAutoPlay']['vDEF'],
'autoPlayInterval' => $pluginConfiguration['autoPlayInterval']['vDEF'],
'enableMouseOver' => $pluginConfiguration['enableMouseOver']['vDEF'],
'hashName' => $pluginConfiguration['hashName']['vDEF']
];
$view->assign('data', $templateData);
$view = $this->previewService->getPluginView($row);
$itemContent .= $view->render();
}
......@@ -110,13 +67,14 @@ class PluginRenderer implements \TYPO3\CMS\Backend\View\PageLayoutViewDrawItemHo
* Adapts the given $headerContent.
* To be used in all plugin previews so the Header Contents appear similarly.
*
* @param $headerContent
* @param $row
* @param string $headerContent
* @param array $row
*/
protected function adaptPluginHeaderContent(&$headerContent, $row): void {
protected function adaptPluginHeaderContent(string &$headerContent, array $row): void {
$headerContent = '<h4>' . $this->getPluginNameForHeaderContent(
(int) $row['pid'], $row['list_type']
) . $headerContent . '</h4>';
(int) $row['pid'],
$row['list_type']
) . $headerContent . '</h4>';
}
/**
......@@ -132,7 +90,10 @@ class PluginRenderer implements \TYPO3\CMS\Backend\View\PageLayoutViewDrawItemHo
$pluginName = $languageService->sL(
BackendUtility::getLabelFromItemListMerged(
$pid, 'tt_content', 'list_type', $listType
$pid,
'tt_content',
'list_type',
$listType
)
);
return '<span class="label label-primary">' . $pluginName . '</span>&nbsp;';
......
<?php
namespace SGalinski\DfTabs\DataProvider;
/***************************************************************
* 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 2 of the License, or
* 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!
***************************************************************/
namespace SGalinski\DfTabs\Preview;
use TYPO3\CMS\Backend\Preview\PreviewRendererInterface;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumnItem;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;
/**
* Data Provider for plain typoscript
*
*/
class TypoScriptDataProvider extends AbstractBaseDataProvider {
class PreviewRenderer implements PreviewRendererInterface {
public const RETURNTYPE_ARR = 'array';
/**
* @var LanguageService $languageService
*/
protected LanguageService $languageService;
protected PreviewService $previewService;
public function __construct(LanguageService $languageService, PreviewService $previewService) {
$this->languageService = $languageService;
$this->previewService = $previewService;
}
/**
* Returns the tab content for the given typoscript object
* Dedicated method for rendering preview header HTML for
* the page module only. Receives $item which is an instance of
* GridColumnItem which has a getter method to return the record.
*
* @param int $uid
* @param GridColumnItem $item
* @return string
*/
public function getTabContent($uid) {
return $this->contentObject->stdWrap(
'', $this->pluginConfiguration['stdWrap.']['typoscriptData.']['tab' . $uid . '.']
public function renderPageModulePreviewHeader(GridColumnItem $item): string {
$label = BackendUtility::getLabelFromItemListMerged(
$item->getRecord()['pid'],
'tt_content',
'list_type',
$item->getRecord()['list_type']
);
return '<h4><span class="label label-primary">' . $this->languageService->sL($label) . '</span>&nbsp;</h4>';
}
/**
* Dedicated method for rendering preview body HTML for
* the page module only.
*
* @param GridColumnItem $item
* @return string
*/
public function renderPageModulePreviewContent(GridColumnItem $item): string {
return $this->previewService->getPluginView($item->getRecord())->render();
}
/**
* Returns an empty string as the titles should be configured with typoscript
* Render a footer for the record to display in page module below
* the body of the item's preview.
*
* @param int $uid
* @param GridColumnItem $item
* @return string
*/
public function getTitle($uid) {
public function renderPageModulePreviewFooter(GridColumnItem $item): string {
return '';
}
/**
* Returns the link data for this typoscript element
* Dedicated method for wrapping a preview header and body HTML.
*
* @param int $uid
* @param string $previewHeader
* @param string $previewContent
* @param GridColumnItem $item
* @return string
*/
public function getLinkData($uid) {
return $this->contentObject->stdWrap(
'', $this->pluginConfiguration['stdWrap.']['typoscriptLinks.']['tab' . $uid . '.']
);
public function wrapPageModulePreview(string $previewHeader, string $previewContent, GridColumnItem $item): string {
return $previewHeader . $previewContent;
}
}
<?php
/***************************************************************
* 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!
***************************************************************/
namespace SGalinski\DfTabs\Preview;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;
/**
* small helper class, aslong as we use PageLayout hook + Previewrenderer....
*/
class PreviewService {
public const RETURNTYPE_ARR = 'array';
public function getPluginView(array $row): StandaloneView {
$view = GeneralUtility::makeInstance(StandaloneView::class);
$view->setPartialRootPaths(['EXT:df_tabs/Resources/Private/Partials/Backend']);
$view->setTemplateRootPaths(['EXT:df_tabs/Resources/Private/Templates/Backend']);
$view->setTemplate('Tabs.html');
$view->assign('uid', $row['uid']);
// Get available plugin settings and their values from flexform
$templateData = [];
// Get available plugin settings and their values from flexform
$pluginConfiguration = GeneralUtility::xml2array(
$row['pi_flexform'],
'T3DataStructure'
)['data']['sDEF']['lDEF'];
$tabElements = GeneralUtility::trimExplode(',', $this->passVDefOnKeyToTemplate($pluginConfiguration, 'data'), TRUE);
$tabs = [];
foreach ($tabElements as $tabElement) {
// Each $tabElement is either 'pages_<id>' or 'tt_content_<id>'.
$recordTable = substr($tabElement, 0, strrpos($tabElement, '_'));
$recordId = substr($tabElement, strrpos($tabElement, '_') + 1);
if ($recordTable === 'pages') {
$recordTitle = BackendUtility::getRecord($recordTable, $recordId, 'title')['title'];
$recordType = 'page';
} elseif ($recordTable === 'tt_content') {
$recordTitle = BackendUtility::getRecord($recordTable, $recordId, 'header')['header'];
$recordType = 'content';
} else {
$recordTitle = $tabElement;
$recordType = 'unknown';
}
$tabs[] = [
'type' => $recordType,
'title' => $recordTitle,
'uid' => $recordId
];
}
$titles = GeneralUtility::trimExplode("\n", $this->passVDefOnKeyToTemplate($pluginConfiguration, 'titles'));
// Remove first item if it is empty to mimic what is actually saved to the DB and frontend behaviour.
// This gets done automatically on a second save of the plugin anyways but it should happen every time.
if ($titles[0] === '') {
array_shift($titles);
}
$templateData = [
'mode' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'mode'),
'tabs' => $tabs,
'titles' => $titles,
'enableAutoPlay' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'enableAutoPlay'),
'autoPlayInterval' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'autoPlayInterval'),
'enableMouseOver' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'enableMouseOver'),
'hashName' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'hashName')
];
$view->assign('data', $templateData);
return $view;
}
/**
* @param array $conf
* @param string $key
* @param string $returnType
* @return array|mixed|string
*/
private function passVDefOnKeyToTemplate(array $conf, string $key, string $returnType = '') {
if (isset($conf[$key])) {
return $conf[$key]['vDEF'];
}
// check if we got a possible returntype:
if ($returnType === self::RETURNTYPE_ARR) {
return [];
}
return '';
}
}
......@@ -121,7 +121,7 @@ class ConfigurationService {
* @return array
*/
protected function getFlexformConfiguration() {
$data =& $this->controllerContext->cObj->data['pi_flexform'];
$data = &$this->controllerContext->cObj->data['pi_flexform'];
$configuration = [];
$value = \trim($this->controllerContext->pi_getFFvalue($data, 'enableAutoPlay'));
......@@ -138,10 +138,15 @@ class ConfigurationService {
if ($value !== '') {
$configuration['autoPlayInterval'] = (int)$value;
}
$value = \trim($this->controllerContext->pi_getFFvalue($data, 'animationSpeed'));
if ($value !== '') {
$configuration['animationSpeed'] = (int)$value;
// this has to be a try catch for now, since animationSpeed was never a Setting inside of our flexform.
// when the Plugin has not been updated, this will stay, throwing an error in php8+
try {
$value = \trim($this->controllerContext->pi_getFFvalue($data, 'animationSpeed'));
if ($value !== '') {
$configuration['animationSpeed'] = (int) $value;
}
} catch (\Exception $e) {
$configuration['animationSpeed'] = 0;
}
$value = \trim($this->controllerContext->pi_getFFvalue($data, 'mode'));
......@@ -155,14 +160,23 @@ class ConfigurationService {
}
### BEGIN Compatibility Code ###
$value = \trim($this->controllerContext->pi_getFFvalue($data, 'pages'));
if ($value !== '') {
$configuration['data'] = $value;
// try catch for reasons explained above
try {