first commit
This commit is contained in:
commit
1218dd1517
12716 files changed
+989233
No files matched your search
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Controller;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Adminpanel\Service\ConfigurationService;
|
||||
use TYPO3\CMS\Adminpanel\Service\ModuleLoader;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Http\JsonResponse;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Admin Panel Ajax Controller - Route endpoint for ajax actions
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class AjaxController
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $adminPanelModuleConfiguration;
|
||||
|
||||
/**
|
||||
* @var ModuleLoader
|
||||
*/
|
||||
protected $moduleLoader;
|
||||
|
||||
/**
|
||||
* @var ConfigurationService
|
||||
*/
|
||||
private $configurationService;
|
||||
|
||||
/**
|
||||
* @param ConfigurationService $configurationService
|
||||
* @param ModuleLoader $moduleLoader
|
||||
*/
|
||||
public function __construct(ConfigurationService $configurationService = null, ModuleLoader $moduleLoader = null)
|
||||
{
|
||||
$this->configurationService = $configurationService
|
||||
??
|
||||
GeneralUtility::makeInstance(ConfigurationService::class);
|
||||
$this->adminPanelModuleConfiguration = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules'] ?? [];
|
||||
$this->moduleLoader = $moduleLoader ?? GeneralUtility::makeInstance(ModuleLoader::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save adminPanel data
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function saveDataAction(ServerRequestInterface $request): JsonResponse
|
||||
{
|
||||
$this->configurationService->saveConfiguration(
|
||||
$this->moduleLoader->validateSortAndInitializeModules($this->adminPanelModuleConfiguration),
|
||||
$request
|
||||
);
|
||||
return new JsonResponse(['success' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle admin panel active state via UC
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function toggleActiveState(): JsonResponse
|
||||
{
|
||||
$backendUser = $this->getBackendUser();
|
||||
if ($backendUser->uc['AdminPanel']['display_top'] ?? false) {
|
||||
$backendUser->uc['AdminPanel']['display_top'] = false;
|
||||
} else {
|
||||
$backendUser->uc['AdminPanel']['display_top'] = true;
|
||||
}
|
||||
$backendUser->writeUC();
|
||||
return new JsonResponse(['success' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current BE user.
|
||||
*
|
||||
* @return BackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUser(): BackendUserAuthentication
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Controller;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ConfigurableInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\DataProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\InitializableInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleDataStorageCollection;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\PageSettingsProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ShortInfoProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\SubmoduleProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\Service\ConfigurationService;
|
||||
use TYPO3\CMS\Adminpanel\Service\ModuleLoader;
|
||||
use TYPO3\CMS\Adminpanel\Utility\ResourceUtility;
|
||||
use TYPO3\CMS\Adminpanel\Utility\StateUtility;
|
||||
use TYPO3\CMS\Adminpanel\View\AdminPanelView;
|
||||
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Core\Cache\CacheManager;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
|
||||
/**
|
||||
* Main controller for the admin panel
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class MainController implements SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var \TYPO3\CMS\Adminpanel\ModuleApi\ModuleInterface[]
|
||||
*/
|
||||
protected $modules = [];
|
||||
|
||||
/**
|
||||
* @var ModuleLoader
|
||||
*/
|
||||
protected $moduleLoader;
|
||||
|
||||
/**
|
||||
* @var UriBuilder
|
||||
*/
|
||||
protected $uriBuilder;
|
||||
|
||||
/**
|
||||
* @var ConfigurationService
|
||||
*/
|
||||
protected $configurationService;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $adminPanelModuleConfiguration;
|
||||
|
||||
/**
|
||||
* @param ModuleLoader $moduleLoader
|
||||
* @param UriBuilder $uriBuilder
|
||||
* @param ConfigurationService $configurationService
|
||||
*/
|
||||
public function __construct(
|
||||
ModuleLoader $moduleLoader = null,
|
||||
UriBuilder $uriBuilder = null,
|
||||
ConfigurationService $configurationService = null
|
||||
) {
|
||||
$this->moduleLoader = $moduleLoader ?? GeneralUtility::makeInstance(ModuleLoader::class);
|
||||
$this->uriBuilder = $uriBuilder ?? GeneralUtility::makeInstance(UriBuilder::class);
|
||||
$this->configurationService = $configurationService
|
||||
??
|
||||
GeneralUtility::makeInstance(ConfigurationService::class);
|
||||
$this->adminPanelModuleConfiguration = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes settings for the admin panel.
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
*/
|
||||
public function initialize(ServerRequestInterface $request): void
|
||||
{
|
||||
$this->modules = $this->moduleLoader->validateSortAndInitializeModules(
|
||||
$this->adminPanelModuleConfiguration
|
||||
);
|
||||
|
||||
if (StateUtility::isActivatedForUser()) {
|
||||
$this->initializeModules($request, $this->modules);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the admin panel - Called in PSR-15 Middleware
|
||||
*
|
||||
* @see \TYPO3\CMS\Adminpanel\Middleware\AdminPanelRenderer
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @return string
|
||||
*/
|
||||
public function render(ServerRequestInterface $request): string
|
||||
{
|
||||
// legacy handling, deprecated, will be removed in TYPO3 v10.0.
|
||||
$adminPanelView = GeneralUtility::makeInstance(AdminPanelView::class);
|
||||
$hookObjectContent = $adminPanelView->callDeprecatedHookObject();
|
||||
// end legacy handling
|
||||
|
||||
$resources = ResourceUtility::getResources();
|
||||
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Main.html';
|
||||
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
|
||||
$view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
|
||||
$view->setLayoutRootPaths(['EXT:adminpanel/Resources/Private/Layouts']);
|
||||
|
||||
$view->assignMultiple(
|
||||
[
|
||||
'toggleActiveUrl' => $this->generateBackendUrl('ajax_adminPanel_toggle'),
|
||||
'resources' => $resources,
|
||||
'adminPanelActive' => StateUtility::isOpen(),
|
||||
]
|
||||
);
|
||||
if (StateUtility::isOpen()) {
|
||||
$cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('adminpanel_requestcache');
|
||||
$requestId = $request->getAttribute('adminPanelRequestId');
|
||||
$data = $cache->get($requestId);
|
||||
$moduleResources = ResourceUtility::getAdditionalResourcesForModules($this->modules);
|
||||
$settingsModules = array_filter($this->modules, function (ModuleInterface $module) {
|
||||
return $module instanceof PageSettingsProviderInterface;
|
||||
});
|
||||
$parentModules = array_filter(
|
||||
$this->modules,
|
||||
function (ModuleInterface $module) {
|
||||
return $module instanceof SubmoduleProviderInterface && $module instanceof ShortInfoProviderInterface;
|
||||
}
|
||||
);
|
||||
$view->assignMultiple(
|
||||
[
|
||||
'modules' => $this->modules,
|
||||
'settingsModules' => $settingsModules,
|
||||
'parentModules' => $parentModules,
|
||||
'hookObjectContent' => $hookObjectContent,
|
||||
'saveUrl' => $this->generateBackendUrl('ajax_adminPanel_saveForm'),
|
||||
'moduleResources' => $moduleResources,
|
||||
'requestId' => $requestId,
|
||||
'data' => $data ?? [],
|
||||
]
|
||||
);
|
||||
}
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores data for admin panel in cache - Called in PSR-15 Middleware
|
||||
*
|
||||
* @see \TYPO3\CMS\Adminpanel\Middleware\AdminPanelDataPersister
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
*/
|
||||
public function storeData(ServerRequestInterface $request): void
|
||||
{
|
||||
if (StateUtility::isOpen()) {
|
||||
$data = $this->storeDataPerModule(
|
||||
$request,
|
||||
$this->modules,
|
||||
GeneralUtility::makeInstance(ModuleDataStorageCollection::class)
|
||||
);
|
||||
$cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('adminpanel_requestcache');
|
||||
$cache->set($request->getAttribute('adminPanelRequestId'), $data);
|
||||
$cache->collectGarbage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a url to a backend route
|
||||
*
|
||||
* @param string $route
|
||||
* @return string
|
||||
*/
|
||||
protected function generateBackendUrl(string $route): string
|
||||
{
|
||||
return (string)$this->uriBuilder->buildUriFromRoute($route);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param \TYPO3\CMS\Adminpanel\ModuleApi\ModuleInterface[] $modules
|
||||
*/
|
||||
protected function initializeModules(ServerRequestInterface $request, array $modules): void
|
||||
{
|
||||
foreach ($modules as $module) {
|
||||
if (
|
||||
($module instanceof InitializableInterface)
|
||||
&& (
|
||||
(($module instanceof ConfigurableInterface) && $module->isEnabled())
|
||||
|| (!($module instanceof ConfigurableInterface))
|
||||
)
|
||||
) {
|
||||
$module->initializeModule($request);
|
||||
}
|
||||
if ($module instanceof SubmoduleProviderInterface) {
|
||||
$this->initializeModules($request, $module->getSubModules());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param \TYPO3\CMS\Adminpanel\ModuleApi\ModuleInterface[] $modules
|
||||
* @param ModuleDataStorageCollection $data
|
||||
* @return ModuleDataStorageCollection
|
||||
*/
|
||||
protected function storeDataPerModule(ServerRequestInterface $request, array $modules, ModuleDataStorageCollection $data): ModuleDataStorageCollection
|
||||
{
|
||||
foreach ($modules as $module) {
|
||||
if (
|
||||
($module instanceof DataProviderInterface)
|
||||
&& (
|
||||
(($module instanceof ConfigurableInterface) && $module->isEnabled())
|
||||
|| (!($module instanceof ConfigurableInterface))
|
||||
)
|
||||
) {
|
||||
$data->addModuleData($module, $module->getDataToStore($request));
|
||||
}
|
||||
|
||||
if ($module instanceof SubmoduleProviderInterface) {
|
||||
$this->storeDataPerModule($request, $module->getSubModules(), $data);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Exceptions;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Exception class for invalid admin panel configuration
|
||||
*/
|
||||
class InvalidConfigurationException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Log;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Doctrine\DBAL\Logging\SQLLogger;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use TYPO3\CMS\Adminpanel\Utility\MemoryUtility;
|
||||
|
||||
/**
|
||||
* Doctrine SQL Logger implementation for recording queries for the admin panel
|
||||
*/
|
||||
class DoctrineSqlLogger implements SQLLogger, LoggerAwareInterface
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
|
||||
/**
|
||||
* Executed SQL queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $queries = [];
|
||||
|
||||
/**
|
||||
* If Debug Stack is enabled (log queries) or not.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $enabled = true;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
protected $start;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $currentQuery = 0;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function startQuery($sql, array $params = null, array $types = null)
|
||||
{
|
||||
if ($this->enabled && MemoryUtility::isMemoryConsumptionTooHigh()) {
|
||||
$this->enabled = false;
|
||||
$this->logger->warning('SQL Logging consumed too much memory, aborted. Not all queries have been recorded.');
|
||||
}
|
||||
if ($this->enabled) {
|
||||
$this->start = microtime(true);
|
||||
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 7);
|
||||
// remove this method
|
||||
array_shift($backtrace);
|
||||
// remove doctrine execute query
|
||||
array_shift($backtrace);
|
||||
// remove queryBuilder execute
|
||||
array_shift($backtrace);
|
||||
$this->queries[++$this->currentQuery] = [
|
||||
'sql' => $sql,
|
||||
'params' => $params,
|
||||
'types' => $types,
|
||||
'executionMS' => 0,
|
||||
'backtrace' => $backtrace
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function stopQuery()
|
||||
{
|
||||
if ($this->enabled) {
|
||||
$this->queries[$this->currentQuery]['executionMS'] = microtime(true) - $this->start;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getQueries(): array
|
||||
{
|
||||
return $this->queries;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Log;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Adminpanel\Utility\MemoryUtility;
|
||||
use TYPO3\CMS\Core\Log\LogLevel;
|
||||
use TYPO3\CMS\Core\Log\LogRecord;
|
||||
use TYPO3\CMS\Core\Log\Writer\AbstractWriter;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Log writer that writes the log records into a static public class variable
|
||||
* for InMemory processing
|
||||
*/
|
||||
class InMemoryLogWriter extends AbstractWriter
|
||||
{
|
||||
public static $log = [];
|
||||
|
||||
private static $memoryLock = false;
|
||||
|
||||
/**
|
||||
* Writes the log record
|
||||
*
|
||||
* @param LogRecord $record Log record
|
||||
* @return self
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function writeLog(LogRecord $record): self
|
||||
{
|
||||
// Guard: Locked Writer
|
||||
if (self::$memoryLock === true) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Guard: Memory Usage
|
||||
if (!self::$memoryLock && MemoryUtility::isMemoryConsumptionTooHigh()) {
|
||||
$this->lockWriter();
|
||||
return $this;
|
||||
}
|
||||
|
||||
self::$log[] = $record;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock writer and add a info message that there may potentially be more entries.
|
||||
*/
|
||||
protected function lockWriter(): void
|
||||
{
|
||||
self::$memoryLock = true;
|
||||
/** @var LogRecord $record */
|
||||
$record = GeneralUtility::makeInstance(
|
||||
LogRecord::class,
|
||||
'TYPO3.CMS.AdminPanel.Log.InMemoryLogWriter',
|
||||
LogLevel::INFO,
|
||||
'... Further log entries omitted, memory usage too high.'
|
||||
);
|
||||
self::$log[] = $record;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Middleware;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use TYPO3\CMS\Adminpanel\Controller\MainController;
|
||||
use TYPO3\CMS\Adminpanel\Utility\StateUtility;
|
||||
use TYPO3\CMS\Core\Http\NullResponse;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
|
||||
/**
|
||||
* Store request data of current request in cache for rendering in admin panel
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class AdminPanelDataPersister implements MiddlewareInterface
|
||||
{
|
||||
/**
|
||||
* Render the admin panel if activated
|
||||
* @param ServerRequestInterface $request
|
||||
* @param RequestHandlerInterface $handler
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
$response = $handler->handle($request);
|
||||
if (
|
||||
!($response instanceof NullResponse)
|
||||
&& $GLOBALS['TSFE'] instanceof TypoScriptFrontendController
|
||||
&& $GLOBALS['TSFE']->isOutputting()
|
||||
&& StateUtility::isActivatedForUser()
|
||||
&& StateUtility::isActivatedInTypoScript()
|
||||
&& !StateUtility::isHiddenForUser()
|
||||
) {
|
||||
$mainController = GeneralUtility::makeInstance(MainController::class);
|
||||
$mainController->storeData($request);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Middleware;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use TYPO3\CMS\Adminpanel\Controller\MainController;
|
||||
use TYPO3\CMS\Adminpanel\Utility\StateUtility;
|
||||
use TYPO3\CMS\Adminpanel\View\AdminPanelView;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* PSR-15 Middleware to initialize the admin panel
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class AdminPanelInitiator implements MiddlewareInterface
|
||||
{
|
||||
/**
|
||||
* Initialize the adminPanel if
|
||||
* - backend user is logged in
|
||||
* - at least one adminpanel functionality is enabled
|
||||
* - admin panel is open
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @param RequestHandlerInterface $handler
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
if (StateUtility::isActivatedForUser() && StateUtility::isOpen()) {
|
||||
$request = $request->withAttribute('adminPanelRequestId', substr(md5(uniqid('', true)), 0, 13));
|
||||
$adminPanelController = GeneralUtility::makeInstance(
|
||||
MainController::class
|
||||
);
|
||||
$adminPanelController->initialize($request);
|
||||
// legacy handling
|
||||
$beUser = $GLOBALS['BE_USER'];
|
||||
$beUser->adminPanel = GeneralUtility::makeInstance(AdminPanelView::class);
|
||||
$beUser->extAdmEnabled = true;
|
||||
}
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Middleware;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use TYPO3\CMS\Adminpanel\Controller\MainController;
|
||||
use TYPO3\CMS\Adminpanel\Utility\StateUtility;
|
||||
use TYPO3\CMS\Core\Http\NullResponse;
|
||||
use TYPO3\CMS\Core\Http\Stream;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
|
||||
/**
|
||||
* Render the admin panel via PSR-15 middleware
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class AdminPanelRenderer implements MiddlewareInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Render the admin panel if activated
|
||||
* @param ServerRequestInterface $request
|
||||
* @param RequestHandlerInterface $handler
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
$response = $handler->handle($request);
|
||||
if (
|
||||
!($response instanceof NullResponse)
|
||||
&& $GLOBALS['TSFE'] instanceof TypoScriptFrontendController
|
||||
&& $GLOBALS['TSFE']->isOutputting()
|
||||
&& StateUtility::isActivatedForUser()
|
||||
&& StateUtility::isActivatedInTypoScript()
|
||||
&& !StateUtility::isHiddenForUser()
|
||||
) {
|
||||
$mainController = GeneralUtility::makeInstance(MainController::class);
|
||||
$body = $response->getBody();
|
||||
$body->rewind();
|
||||
$contents = $response->getBody()->getContents();
|
||||
$content = str_ireplace(
|
||||
'</body>',
|
||||
$mainController->render($request) . '</body>',
|
||||
$contents
|
||||
);
|
||||
$body = new Stream('php://temp', 'rw');
|
||||
$body->write($content);
|
||||
$response = $response->withBody($body);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Middleware;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use TYPO3\CMS\Adminpanel\Log\DoctrineSqlLogger;
|
||||
use TYPO3\CMS\Adminpanel\Utility\StateUtility;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Enable sql logging for the admin panel
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class SqlLogging implements MiddlewareInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Enable SQL Logging as early as possible to catch all queries if the admin panel is active
|
||||
* @param ServerRequestInterface $request
|
||||
* @param RequestHandlerInterface $handler
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
if (StateUtility::isActivatedForUser() && StateUtility::isOpen()) {
|
||||
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
|
||||
$connection = $connectionPool->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
|
||||
$connection->getConfiguration()->setSQLLogger(GeneralUtility::makeInstance(DoctrineSqlLogger::class));
|
||||
}
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ModuleApi;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Adminpanel\Service\ConfigurationService;
|
||||
use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Abstract base class for Admin Panel Modules containing helper methods and default interface implementations
|
||||
* Extend this class when writing own admin panel modules (or implement the Interface directly)
|
||||
*/
|
||||
abstract class AbstractModule implements ModuleInterface, ConfigurableInterface, SubmoduleProviderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @var ModuleInterface[]
|
||||
*/
|
||||
protected $subModules = [];
|
||||
|
||||
/**
|
||||
* Main Configuration (from UserTSConfig, admPanel)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $mainConfiguration;
|
||||
|
||||
/**
|
||||
* @var ConfigurationService
|
||||
*/
|
||||
protected $configurationService;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
|
||||
$this->mainConfiguration = $this->configurationService->getMainConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the module is
|
||||
* -> either enabled via TSConfig admPanel.enable
|
||||
* -> or any setting is overridden
|
||||
* override is a way to use functionality of the admin panel without displaying the admin panel to users
|
||||
* for example: hidden records or pages can be displayed by default
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
$identifier = $this->getIdentifier();
|
||||
$result = $this->isEnabledViaTsConfig();
|
||||
if ($this->mainConfiguration['override.'][$identifier] ?? false) {
|
||||
$result = (bool)$this->mainConfiguration['override.'][$identifier];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function setSubModules(array $subModules): void
|
||||
{
|
||||
$this->subModules = $subModules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getSubModules(): array
|
||||
{
|
||||
return $this->subModules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function hasSubmoduleSettings(): bool
|
||||
{
|
||||
$hasSettings = false;
|
||||
foreach ($this->subModules as $subModule) {
|
||||
if ($subModule instanceof ModuleSettingsProviderInterface) {
|
||||
$hasSettings = true;
|
||||
break;
|
||||
}
|
||||
if ($subModule instanceof SubmoduleProviderInterface) {
|
||||
$hasSettings = $subModule->hasSubmoduleSettings();
|
||||
}
|
||||
}
|
||||
return $hasSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current BE user.
|
||||
*
|
||||
* @return BackendUserAuthentication|FrontendBackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUser(): BackendUserAuthentication
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns LanguageService
|
||||
*
|
||||
* @return LanguageService
|
||||
*/
|
||||
protected function getLanguageService(): LanguageService
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if TSConfig admPanel.enable is set for this module (or all modules)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isEnabledViaTsConfig(): bool
|
||||
{
|
||||
$result = false;
|
||||
$identifier = $this->getIdentifier();
|
||||
if (!empty($this->mainConfiguration['enable.']['all'])) {
|
||||
$result = true;
|
||||
} elseif (!empty($this->mainConfiguration['enable.'][$identifier])) {
|
||||
$result = true;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ModuleApi;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
|
||||
/**
|
||||
* Abstract SubModule - Base class for sub modules in the admin panel
|
||||
*
|
||||
* Extend this class when writing own sub modules
|
||||
*/
|
||||
abstract class AbstractSubModule implements ModuleInterface, ContentProviderInterface
|
||||
{
|
||||
/**
|
||||
* Returns LanguageService
|
||||
*
|
||||
* @return LanguageService
|
||||
*/
|
||||
protected function getLanguageService(): LanguageService
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ModuleApi;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
/**
|
||||
* AdminPanel ConfigurableInterface
|
||||
*
|
||||
* Used to indicate that an adminpanel module can be enabled or disabled via configuration
|
||||
*
|
||||
* Usual implementation is done via user tsconfig
|
||||
* @see \TYPO3\CMS\Adminpanel\ModuleApi\AbstractModule::isEnabled()
|
||||
*/
|
||||
interface ConfigurableInterface
|
||||
{
|
||||
/**
|
||||
* Module is enabled
|
||||
* -> should be initialized
|
||||
* A module may be enabled but not shown
|
||||
* -> only the initializeModule() method
|
||||
* will be called
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEnabled(): bool;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ModuleApi;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adminpanel interface to denote that a module has content to be rendered
|
||||
*
|
||||
* In general there are two main types of admin panel modules: those providing settings influencing page rendering
|
||||
* (for example the preview module provides settings for displaying hidden pages or records) and those rendering
|
||||
* information regarding the current request (for example the log module).
|
||||
*
|
||||
* Modules implementing this interface denote that they render module content.
|
||||
*/
|
||||
interface ContentProviderInterface
|
||||
{
|
||||
/**
|
||||
* Main method for content generation of an admin panel module.
|
||||
* Return content as HTML. For modules implementing the DataProviderInterface
|
||||
* the "ModuleData" object is automatically filled with the stored data - if
|
||||
* no data is given a "fresh" ModuleData object is injected.
|
||||
*
|
||||
* @param \TYPO3\CMS\Adminpanel\ModuleApi\ModuleData $data
|
||||
* @return string
|
||||
*/
|
||||
public function getContent(ModuleData $data): string;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ModuleApi;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* Adminpanel interface to denote that a module provides data to be stored for the current request
|
||||
*
|
||||
* Adminpanel modules can save data to the adminpanel request cache and access this data in the rendering process.
|
||||
* Data necessary for rendering the module content has to be returned via this interface implementation, as this allows
|
||||
* for separate data collection and rendering and is a pre-requisite for a standalone debug tool.
|
||||
*/
|
||||
interface DataProviderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @return \TYPO3\CMS\Adminpanel\ModuleApi\ModuleData
|
||||
*/
|
||||
public function getDataToStore(ServerRequestInterface $request): ModuleData;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ModuleApi;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* Adminpanel interface to denote that a module has tasks to perform on initialization of the request
|
||||
*
|
||||
* Modules that need to set data / options early in the rendering process to be able to collect data, should implement
|
||||
* this interface - for example the log module uses the initialization to register the admin panel log collection early
|
||||
* in the rendering process.
|
||||
*
|
||||
* Initialize is called in the PSR-15 middleware stack through admin panel initialisation via the AdminPanel MainController.
|
||||
*
|
||||
* @see \TYPO3\CMS\Adminpanel\Middleware\AdminPanelInitiator::process()
|
||||
* @see \TYPO3\CMS\Adminpanel\Controller\MainController::initialize()
|
||||
*/
|
||||
interface InitializableInterface
|
||||
{
|
||||
/**
|
||||
* Initialize the module - runs early in a TYPO3 request
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
*/
|
||||
public function initializeModule(ServerRequestInterface $request): void;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ModuleApi;
|
||||
|
||||
/**
|
||||
* ModuleData is a simple wrapper object which extends ArrayObject
|
||||
* which is used to hold Adminpanel module data
|
||||
*
|
||||
* It's a separate class to add semantic meaning to its' usage
|
||||
*/
|
||||
class ModuleData extends \ArrayObject
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ModuleApi;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
/**
|
||||
* ModuleDataStorageCollection is an object storage for adminpanel modules and their data
|
||||
*/
|
||||
class ModuleDataStorageCollection extends \SplObjectStorage
|
||||
{
|
||||
public function addModuleData(DataProviderInterface $module, ModuleData $moduleData): void
|
||||
{
|
||||
$this->attach($module, $moduleData);
|
||||
}
|
||||
|
||||
public function getHash($object)
|
||||
{
|
||||
if ($object instanceof ModuleInterface) {
|
||||
return $object->getIdentifier();
|
||||
}
|
||||
throw new \InvalidArgumentException(
|
||||
'Only modules implementing ' . ModuleInterface::class . ' are allowed to be stored',
|
||||
1535301628
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ModuleApi;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adminpanel interface for all modules
|
||||
*
|
||||
* Every adminpanel module needs to implement this interface as a bare minimum.
|
||||
*/
|
||||
interface ModuleInterface
|
||||
{
|
||||
/**
|
||||
* Identifier for this module,
|
||||
* for example "preview" or "cache"
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier(): string;
|
||||
|
||||
/**
|
||||
* Module label
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLabel(): string;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ModuleApi;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adminpanel module settings interface denotes that a module has own settings.
|
||||
*
|
||||
* The adminpanel knows two types of settings:
|
||||
* - ModuleSettings are relevant for the module itself and its representation (for example the log module provides settings
|
||||
* where displayed log level and grouping of the module can be configured)
|
||||
* - PageSettings are relevant for rendering the page (for example the preview module provides settings showing or hiding
|
||||
* hidden content elements or simulating a specific rendering time)
|
||||
*
|
||||
* If a module provides settings relevant to its own content, use this interface.
|
||||
*
|
||||
* @see \TYPO3\CMS\Adminpanel\ModuleApi\PageSettingsProviderInterface
|
||||
*/
|
||||
interface ModuleSettingsProviderInterface
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSettings(): string;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ModuleApi;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* Adminpanel interface for modules that need to react on changed configuration
|
||||
* (for example if fluid debug settings change, the frontend cache should be cleared)
|
||||
*/
|
||||
interface OnSubmitActorInterface
|
||||
{
|
||||
/**
|
||||
* Executed on saving / submit of the configuration form
|
||||
* Can be used to react to changed settings
|
||||
* (for example: clearing a specific cache)
|
||||
*
|
||||
* @param array $configurationToSave
|
||||
* @param ServerRequestInterface $request
|
||||
*/
|
||||
public function onSubmit(array $configurationToSave, ServerRequestInterface $request): void;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ModuleApi;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adminpanel page settings interface denotes that a module has settings regarding the page rendering.
|
||||
* The adminpanel knows two types of settings:
|
||||
* - ModuleSettings are relevant for the module itself and its representation (for example the log module provides settings
|
||||
* where displayed log level and grouping of the module can be configured)
|
||||
* - PageSettings are relevant for rendering the page (for example the preview module provides settings showing or hiding
|
||||
* hidden content elements or simulating a specific rendering time)
|
||||
* If a module provides settings changing the rendering of the main page request, use this interface.
|
||||
*
|
||||
* @see \TYPO3\CMS\Adminpanel\ModuleApi\ModuleSettingsProviderInterface
|
||||
*/
|
||||
interface PageSettingsProviderInterface
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPageSettings(): string;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ModuleApi;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adminpanel interface to denote that a module has own resource files.
|
||||
*
|
||||
* An adminpanel module implementing this interface may deliver custom JavaScript and Css files to provide additional
|
||||
* styling and JavaScript functionality
|
||||
*/
|
||||
interface ResourceProviderInterface
|
||||
{
|
||||
/**
|
||||
* Returns a string array with javascript files that will be rendered after the module
|
||||
*
|
||||
* Example: return ['EXT:adminpanel/Resources/Public/JavaScript/Modules/Edit.js'];
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getJavaScriptFiles(): array;
|
||||
|
||||
/**
|
||||
* Returns a string array with css files that will be rendered after the module
|
||||
*
|
||||
* Example: return ['EXT:adminpanel/Resources/Public/JavaScript/Modules/Edit.css'];
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCssFiles(): array;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ModuleApi;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adminpanel shortinfo provider interface can be used to add the module to the short info bar of the adminpanel
|
||||
*
|
||||
* Modules providing shortinfo will be displayed in the bottom bar of the adminpanel and may provide "at a glance" info
|
||||
* about the current state (for example the log module provides the number of warnings and errors directly).
|
||||
*
|
||||
* Be aware that modules with submodules at the moment can only render one short info (the one of the "parent" module).
|
||||
* This will likely change in TYPO3 v10.0.
|
||||
*/
|
||||
interface ShortInfoProviderInterface
|
||||
{
|
||||
/**
|
||||
* Displayed directly in the bar
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getShortInfo(): string;
|
||||
|
||||
/**
|
||||
* Icon identifier - needs to be registered in iconRegistry
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIconIdentifier(): string;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ModuleApi;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adminpanel interface providing hierarchical functionality for modules
|
||||
*
|
||||
* A module implementing this interface may have submodules. Be aware that the current implementation of the adminpanel
|
||||
* renders a maximum level of 2 for modules. If you need to render more levels, write your own module and implement
|
||||
* multi-hierarchical rendering in the getContent method
|
||||
*
|
||||
* @see \TYPO3\CMS\Adminpanel\ModuleApi\ContentProviderInterface::getContent()
|
||||
*/
|
||||
interface SubmoduleProviderInterface
|
||||
{
|
||||
/**
|
||||
* Sets array of module instances (instances of `ModuleInterface`) as submodules
|
||||
*
|
||||
* @param \TYPO3\CMS\Adminpanel\ModuleApi\ModuleInterface[] $subModules
|
||||
*/
|
||||
public function setSubModules(array $subModules): void;
|
||||
|
||||
/**
|
||||
* Returns an array of module instances
|
||||
*
|
||||
* @return \TYPO3\CMS\Adminpanel\ModuleApi\ModuleInterface[]
|
||||
*/
|
||||
public function getSubModules(): array;
|
||||
|
||||
/**
|
||||
* Return true if any of the submodules has settings to be rendered
|
||||
* (can be used to render settings in a central place)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasSubmoduleSettings(): bool;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Modules;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\AbstractModule;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\InitializableInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\PageSettingsProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ResourceProviderInterface;
|
||||
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
|
||||
class CacheModule extends AbstractModule implements PageSettingsProviderInterface, InitializableInterface, ResourceProviderInterface
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIconIdentifier(): string
|
||||
{
|
||||
return 'apps-toolbar-menu-cache';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPageSettings(): string
|
||||
{
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Modules/Settings/Cache.html';
|
||||
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
|
||||
$view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
|
||||
|
||||
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
|
||||
$feCacheClear = $this->getBackendUser()->isAdmin() || $this->getBackendUser()->getTSConfig()['options.']['clearCache.']['pages'];
|
||||
|
||||
$view->assignMultiple(
|
||||
[
|
||||
'isEnabled' => $this->getBackendUser()->uc['AdminPanel']['display_cache'],
|
||||
'noCache' => $this->getBackendUser()->uc['AdminPanel']['cache_noCache'],
|
||||
'currentId' => $this->getTypoScriptFrontendController()->id,
|
||||
'clearPageCacheUrl' => $feCacheClear ? (string)$uriBuilder->buildUriFromRoute('tce_db', ['cacheCmd' => 'pages']) : '',
|
||||
'clearCurrentPageCacheUrl' => (string)$uriBuilder->buildUriFromRoute(
|
||||
'tce_db',
|
||||
[
|
||||
'cacheCmd' => $this->getTypoScriptFrontendController()->id,
|
||||
]
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return 'cache';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getLabel(): string
|
||||
{
|
||||
$locallangFileAndPath = 'LLL:EXT:adminpanel/Resources/Private/Language/locallang_cache.xlf:module.label';
|
||||
return $this->getLanguageService()->sL($locallangFileAndPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function initializeModule(ServerRequestInterface $request): void
|
||||
{
|
||||
if ($this->configurationService->getConfigurationOption('cache', 'noCache')) {
|
||||
$this->getTypoScriptFrontendController()->set_no_cache('Admin Panel: No Caching', true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TypoScriptFrontendController
|
||||
*/
|
||||
protected function getTypoScriptFrontendController(): TypoScriptFrontendController
|
||||
{
|
||||
return $GLOBALS['TSFE'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getJavaScriptFiles(): array
|
||||
{
|
||||
return ['EXT:adminpanel/Resources/Public/JavaScript/Modules/Cache.js'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string array with css files that will be rendered after the module
|
||||
*
|
||||
* Example: return ['EXT:adminpanel/Resources/Public/JavaScript/Modules/Edit.css'];
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCssFiles(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Modules\Debug;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Adminpanel\Log\InMemoryLogWriter;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\AbstractSubModule;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\DataProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\InitializableInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleData;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleSettingsProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\Service\ConfigurationService;
|
||||
use TYPO3\CMS\Core\Log\LogLevel;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
|
||||
/**
|
||||
* Log Sub Module of the AdminPanel
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class Log extends AbstractSubModule implements DataProviderInterface, ModuleSettingsProviderInterface, InitializableInterface
|
||||
{
|
||||
protected $logLevel = LogLevel::INFO;
|
||||
|
||||
/**
|
||||
* @var ConfigurationService
|
||||
*/
|
||||
protected $configurationService;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return 'debug_log';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub-Module label
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLabel(): string
|
||||
{
|
||||
return $this->getLanguageService()->sL(
|
||||
'LLL:EXT:adminpanel/Resources/Private/Language/locallang_debug.xlf:submodule.log.label'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getDataToStore(ServerRequestInterface $request): ModuleData
|
||||
{
|
||||
$levels = [];
|
||||
for ($i = 1; $i <= LogLevel::DEBUG; $i++) {
|
||||
$levels[] = [
|
||||
'level' => $i,
|
||||
'levelName' => LogLevel::getName($i),
|
||||
];
|
||||
}
|
||||
|
||||
$log = InMemoryLogWriter::$log;
|
||||
|
||||
$logArray = [];
|
||||
/** @var \TYPO3\CMS\Core\Log\LogRecord $logRecord */
|
||||
foreach ($log as $logRecord) {
|
||||
$entry = $logRecord->toArray();
|
||||
// store only necessary info
|
||||
unset($entry['data']);
|
||||
$logArray[] = $entry;
|
||||
}
|
||||
return new ModuleData(
|
||||
[
|
||||
'levels' => $levels,
|
||||
'startLevel' => (int)$this->getConfigOption('startLevel'),
|
||||
'log' => $logArray,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getSettings(): string
|
||||
{
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Modules/Debug/LogSettings.html';
|
||||
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
|
||||
$view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
|
||||
|
||||
$levels = [];
|
||||
for ($i = 1; $i <= LogLevel::DEBUG; $i++) {
|
||||
$levels[] = [
|
||||
'level' => $i,
|
||||
'levelName' => LogLevel::getName($i),
|
||||
];
|
||||
}
|
||||
$view->assignMultiple(
|
||||
[
|
||||
'levels' => $levels,
|
||||
'startLevel' => (int)$this->getConfigOption('startLevel'),
|
||||
'groupByComponent' => $this->getConfigOption('groupByComponent'),
|
||||
'groupByLevel' => $this->getConfigOption('groupByLevel'),
|
||||
]
|
||||
);
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub-Module content as rendered HTML
|
||||
*
|
||||
* @param \TYPO3\CMS\Adminpanel\ModuleApi\ModuleData $data
|
||||
* @return string
|
||||
*/
|
||||
public function getContent(ModuleData $data): string
|
||||
{
|
||||
$this->logLevel = $this->getConfigOption('startLevel');
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Modules/Debug/Log.html';
|
||||
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
|
||||
$view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
|
||||
$sortedLog = [];
|
||||
// settings for this module
|
||||
$groupByComponent = $this->getConfigOption('groupByComponent');
|
||||
$groupByLevel = $this->getConfigOption('groupByLevel');
|
||||
|
||||
foreach ($data['log'] as $logRecord) {
|
||||
if ($logRecord['level'] > $this->logLevel) {
|
||||
continue;
|
||||
}
|
||||
if ($groupByComponent && $groupByLevel) {
|
||||
$sortedLog[$logRecord['component']][LogLevel::getName($logRecord['level'])][] = $logRecord;
|
||||
} elseif ($groupByComponent) {
|
||||
$sortedLog[$logRecord['component']][] = $logRecord;
|
||||
} elseif ($groupByLevel) {
|
||||
$sortedLog[$logRecord['level']][] = $logRecord;
|
||||
} else {
|
||||
$sortedLog[] = $logRecord;
|
||||
}
|
||||
}
|
||||
$data['log'] = $sortedLog;
|
||||
$data['groupByComponent'] = $groupByComponent;
|
||||
$data['groupByLevel'] = $groupByLevel;
|
||||
$view->assignMultiple($data->getArrayCopy());
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function initializeModule(ServerRequestInterface $request): void
|
||||
{
|
||||
$this->logLevel = $this->getConfigOption('startLevel');
|
||||
|
||||
// set inMemoryLogWriter recursively for all configured namespaces/areas so we don't lose log entries
|
||||
$configWithInMemoryWriter = $this->setLoggingConfigRecursive($GLOBALS['TYPO3_CONF_VARS']['LOG'] ?? []);
|
||||
|
||||
// in case there are empty array parts, remove them
|
||||
$GLOBALS['TYPO3_CONF_VARS']['LOG'] = array_filter(
|
||||
$configWithInMemoryWriter
|
||||
);
|
||||
}
|
||||
|
||||
protected function setLoggingConfigRecursive(array $logConfig): array
|
||||
{
|
||||
foreach ($logConfig as $key => $value) {
|
||||
if ($key === 'writerConfiguration') {
|
||||
$logConfig[$key] = $value;
|
||||
$logConfig[$key][LogLevel::DEBUG][InMemoryLogWriter::class] = [];
|
||||
} elseif (is_array($value)) {
|
||||
$logConfig[$key] = $this->setLoggingConfigRecursive($value);
|
||||
}
|
||||
}
|
||||
return $logConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $option
|
||||
* @return string
|
||||
*/
|
||||
protected function getConfigOption(string $option): string
|
||||
{
|
||||
return $this->configurationService->getConfigurationOption('debug_log', $option);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Modules\Debug;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Adminpanel\Log\DoctrineSqlLogger;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\AbstractSubModule;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\DataProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleData;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
|
||||
/**
|
||||
* Admin Panel Query Information module for showing SQL Queries
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class QueryInformation extends AbstractSubModule implements DataProviderInterface
|
||||
{
|
||||
/**
|
||||
* Identifier for this Sub-module,
|
||||
* for example "preview" or "cache"
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return 'debug_queryinformation';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub-Module label
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLabel(): string
|
||||
{
|
||||
return $this->getLanguageService()->sL(
|
||||
'LLL:EXT:adminpanel/Resources/Private/Language/locallang_debug.xlf:submodule.queryInformation.label'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @return \TYPO3\CMS\Adminpanel\ModuleApi\ModuleData
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function getDataToStore(ServerRequestInterface $request): ModuleData
|
||||
{
|
||||
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
|
||||
$connection = $connectionPool->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
|
||||
$logger = $connection->getConfiguration()->getSQLLogger();
|
||||
$data = [];
|
||||
if ($logger instanceof DoctrineSqlLogger) {
|
||||
$queries = $logger->getQueries();
|
||||
$data['queries'] = $this->groupQueries($queries) ?? [];
|
||||
$data['totalTime'] = array_sum(array_column($queries, 'executionMS')) * 1000;
|
||||
}
|
||||
return new ModuleData($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \TYPO3\CMS\Adminpanel\ModuleApi\ModuleData $data
|
||||
* @return string Returns content of admin panel
|
||||
*/
|
||||
public function getContent(ModuleData $data): string
|
||||
{
|
||||
$view = new StandaloneView();
|
||||
$view->setTemplatePathAndFilename(
|
||||
'EXT:adminpanel/Resources/Private/Templates/Modules/Debug/QueryInformation.html'
|
||||
);
|
||||
$this->getLanguageService()->includeLLFile('EXT:adminpanel/Resources/Private/Language/locallang_debug.xlf');
|
||||
$view->assignMultiple($data->getArrayCopy());
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $queries
|
||||
* @return array
|
||||
*/
|
||||
protected function groupQueries(array $queries): array
|
||||
{
|
||||
$groupedQueries = [];
|
||||
foreach ($queries as $query) {
|
||||
$identifier = sha1($query['sql']) . sha1(json_encode($query['backtrace']));
|
||||
if (is_array($query['params'])) {
|
||||
foreach ($query['params'] as $k => $param) {
|
||||
if (is_array($param)) {
|
||||
$query['params'][$k] = implode(',', $param);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($groupedQueries[$identifier])) {
|
||||
$groupedQueries[$identifier]['count']++;
|
||||
$groupedQueries[$identifier]['time'] += ($query['executionMS'] * 1000);
|
||||
$groupedQueries[$identifier]['queries'][] = $query;
|
||||
} else {
|
||||
$groupedQueries[$identifier] = [
|
||||
'sql' => $query['sql'],
|
||||
'time' => $query['executionMS'] * 1000,
|
||||
'count' => 1,
|
||||
'queries' => [
|
||||
$query,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
uasort(
|
||||
$groupedQueries,
|
||||
function ($a, $b) {
|
||||
return $b['time'] <=> $a['time'];
|
||||
}
|
||||
);
|
||||
return $groupedQueries;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Modules;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Adminpanel\Log\InMemoryLogWriter;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\AbstractModule;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ShortInfoProviderInterface;
|
||||
use TYPO3\CMS\Core\Log\LogRecord;
|
||||
|
||||
/**
|
||||
* Debug Module of the AdminPanel
|
||||
*/
|
||||
class DebugModule extends AbstractModule implements ShortInfoProviderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return 'debug';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIconIdentifier(): string
|
||||
{
|
||||
return 'actions-debug';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getLabel(): string
|
||||
{
|
||||
return $this->getLanguageService()->sL(
|
||||
'LLL:EXT:adminpanel/Resources/Private/Language/locallang_debug.xlf:module.label'
|
||||
);
|
||||
}
|
||||
|
||||
public function getShortInfo(): string
|
||||
{
|
||||
$errorsAndWarnings = array_filter(InMemoryLogWriter::$log, function (LogRecord $entry) {
|
||||
return $entry->getLevel() <= 4;
|
||||
});
|
||||
return sprintf($this->getLanguageService()->sL(
|
||||
'LLL:EXT:adminpanel/Resources/Private/Language/locallang_debug.xlf:module.shortinfo'
|
||||
), count($errorsAndWarnings));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Modules;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\AbstractModule;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\InitializableInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\PageSettingsProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ResourceProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\Service\EditToolbarService;
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
|
||||
/**
|
||||
* Admin Panel Edit Module
|
||||
*/
|
||||
class EditModule extends AbstractModule implements PageSettingsProviderInterface, InitializableInterface, ResourceProviderInterface
|
||||
{
|
||||
/**
|
||||
* Creates the content for the "edit" section ("module") of the Admin Panel
|
||||
*
|
||||
* @return string HTML content for the section. Consists of a string with table-rows with four columns.
|
||||
*/
|
||||
public function getPageSettings(): string
|
||||
{
|
||||
$editToolbarService = GeneralUtility::makeInstance(EditToolbarService::class);
|
||||
$toolbar = $editToolbarService->createToolbar();
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Modules/Settings/Edit.html';
|
||||
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
|
||||
$view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
|
||||
$view->assignMultiple(
|
||||
[
|
||||
'feEdit' => ExtensionManagementUtility::isLoaded('feedit'),
|
||||
'display' => [
|
||||
'fieldIcons' => $this->configurationService->getConfigurationOption('edit', 'displayFieldIcons'),
|
||||
'displayIcons' => $this->configurationService->getConfigurationOption('edit', 'displayIcons'),
|
||||
],
|
||||
'toolbar' => $toolbar,
|
||||
'script' => [
|
||||
'pageUid' => (int)$this->getTypoScriptFrontendController()->page['uid'],
|
||||
'pageModule' => $this->getPageModule(),
|
||||
'backendScript' => BackendUtility::getBackendScript(),
|
||||
't3BeSitenameMd5' => md5('Typo3Backend-' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']),
|
||||
],
|
||||
]
|
||||
);
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TypoScriptFrontendController
|
||||
*/
|
||||
protected function getTypoScriptFrontendController(): TypoScriptFrontendController
|
||||
{
|
||||
return $GLOBALS['TSFE'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function getPageModule(): string
|
||||
{
|
||||
$pageModule = trim($this->getBackendUser()->getTSConfig()['options.']['overridePageModule'] ?? '');
|
||||
return BackendUtility::isModuleSetInTBE_MODULES($pageModule) ? $pageModule : 'web_layout';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return 'edit';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIconIdentifier(): string
|
||||
{
|
||||
return 'actions-open';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getLabel(): string
|
||||
{
|
||||
$locallangFileAndPath = 'LLL:EXT:adminpanel/Resources/Private/Language/locallang_edit.xlf:module.label';
|
||||
return $this->getLanguageService()->sL($locallangFileAndPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the edit module
|
||||
* Includes the frontend edit initialization
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @todo move into fe_edit (including the module)
|
||||
*/
|
||||
public function initializeModule(ServerRequestInterface $request): void
|
||||
{
|
||||
$extFeEditLoaded = ExtensionManagementUtility::isLoaded('feedit');
|
||||
$typoScriptFrontend = $this->getTypoScriptFrontendController();
|
||||
$typoScriptFrontend->displayEditIcons = $this->configurationService->getConfigurationOption('edit', 'displayIcons');
|
||||
$typoScriptFrontend->displayFieldEditIcons = $this->configurationService->getConfigurationOption('edit', 'displayFieldIcons');
|
||||
|
||||
if ($request->getQueryParams()['ADMCMD_editIcons'] ?? $request->getParsedBody()['ADMCMD_editIcons'] ?? false) {
|
||||
$typoScriptFrontend->displayFieldEditIcons = '1';
|
||||
}
|
||||
if ($extFeEditLoaded && $typoScriptFrontend->displayEditIcons) {
|
||||
$typoScriptFrontend->set_no_cache('Admin Panel: Display edit icons', true);
|
||||
}
|
||||
if ($extFeEditLoaded && $typoScriptFrontend->displayFieldEditIcons) {
|
||||
$typoScriptFrontend->set_no_cache('Admin Panel: Display field edit icons', true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getJavaScriptFiles(): array
|
||||
{
|
||||
return ['EXT:adminpanel/Resources/Public/JavaScript/Modules/Edit.js'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string array with css files that will be rendered after the module
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCssFiles(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Modules\Info;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\AbstractSubModule;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\DataProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleData;
|
||||
use TYPO3\CMS\Core\Context\Context;
|
||||
use TYPO3\CMS\Core\Context\UserAspect;
|
||||
use TYPO3\CMS\Core\TimeTracker\TimeTracker;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
|
||||
/**
|
||||
* General information module displaying info about the current
|
||||
* request
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class GeneralInformation extends AbstractSubModule implements DataProviderInterface
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getDataToStore(ServerRequestInterface $request): ModuleData
|
||||
{
|
||||
/** @var UserAspect $frontendUserAspect */
|
||||
$frontendUserAspect = GeneralUtility::makeInstance(Context::class)->getAspect('frontend.user');
|
||||
$tsfe = $this->getTypoScriptFrontendController();
|
||||
return new ModuleData(
|
||||
[
|
||||
'post' => $_POST,
|
||||
'get' => $_GET,
|
||||
'cookie' => $_COOKIE,
|
||||
'server' => $_SERVER,
|
||||
'info' => [
|
||||
'pageUid' => $tsfe->id,
|
||||
'pageType' => $tsfe->type,
|
||||
'groupList' => implode(',', $frontendUserAspect->getGroupIds()),
|
||||
'noCache' => $this->isNoCacheEnabled(),
|
||||
'countUserInt' => count($tsfe->config['INTincScript'] ?? []),
|
||||
'totalParsetime' => $this->getTimeTracker()->getParseTime(),
|
||||
'feUser' => [
|
||||
'uid' => $frontendUserAspect->get('id') ?: 0,
|
||||
'username' => $frontendUserAspect->get('username') ?: '',
|
||||
],
|
||||
'imagesOnPage' => $this->collectImagesOnPage(),
|
||||
'documentSize' => $this->collectDocumentSize(),
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the content for the "info" section ("module") of the Admin Panel
|
||||
*
|
||||
* @param \TYPO3\CMS\Adminpanel\ModuleApi\ModuleData $data
|
||||
* @return string HTML content for the section. Consists of a string with table-rows with four columns.
|
||||
* @see display()
|
||||
*/
|
||||
public function getContent(ModuleData $data): string
|
||||
{
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Modules/Info/General.html';
|
||||
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
|
||||
$view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
|
||||
|
||||
$view->assignMultiple($data->getArrayCopy());
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifier for this Sub-module,
|
||||
* for example "preview" or "cache"
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return 'info_general';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getLabel(): string
|
||||
{
|
||||
return $this->getLanguageService()->sL(
|
||||
'LLL:EXT:adminpanel/Resources/Private/Language/locallang_info.xlf:sub.general.label'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects images from TypoScriptFrontendController and calculates the total size.
|
||||
* Returns human readable image sizes for fluid template output
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function collectImagesOnPage(): array
|
||||
{
|
||||
$imagesOnPage = [
|
||||
'files' => [],
|
||||
'total' => 0,
|
||||
'totalSize' => 0,
|
||||
'totalSizeHuman' => GeneralUtility::formatSize(0),
|
||||
];
|
||||
|
||||
if ($this->isNoCacheEnabled() === false) {
|
||||
return $imagesOnPage;
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
$totalImageSize = 0;
|
||||
if (!empty($this->getTypoScriptFrontendController()->imagesOnPage)) {
|
||||
foreach ($this->getTypoScriptFrontendController()->imagesOnPage as $file) {
|
||||
$fileSize = @filesize($file);
|
||||
$imagesOnPage['files'][] = [
|
||||
'name' => $file,
|
||||
'size' => $fileSize,
|
||||
'sizeHuman' => GeneralUtility::formatSize($fileSize),
|
||||
];
|
||||
$totalImageSize += $fileSize;
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
$imagesOnPage['totalSize'] = GeneralUtility::formatSize($totalImageSize);
|
||||
$imagesOnPage['total'] = $count;
|
||||
return $imagesOnPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the document size from the current page in a human readable format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function collectDocumentSize(): string
|
||||
{
|
||||
$documentSize = 0;
|
||||
if ($this->isNoCacheEnabled() === true) {
|
||||
$documentSize = mb_strlen($this->getTypoScriptFrontendController()->content, 'UTF-8');
|
||||
}
|
||||
|
||||
return GeneralUtility::formatSize($documentSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function isNoCacheEnabled(): bool
|
||||
{
|
||||
return (bool)$this->getTypoScriptFrontendController()->no_cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TypoScriptFrontendController
|
||||
*/
|
||||
protected function getTypoScriptFrontendController(): TypoScriptFrontendController
|
||||
{
|
||||
return $GLOBALS['TSFE'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TimeTracker
|
||||
*/
|
||||
protected function getTimeTracker(): TimeTracker
|
||||
{
|
||||
return GeneralUtility::makeInstance(TimeTracker::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Modules\Info;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\AbstractSubModule;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\DataProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleData;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
|
||||
/**
|
||||
* PhpInformation admin panel sub module
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class PhpInformation extends AbstractSubModule implements DataProviderInterface
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return 'info_php';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getLabel(): string
|
||||
{
|
||||
return $this->getLanguageService()->sL(
|
||||
'LLL:EXT:adminpanel/Resources/Private/Language/locallang_info.xlf:sub.php.label'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getDataToStore(ServerRequestInterface $request): ModuleData
|
||||
{
|
||||
return new ModuleData(
|
||||
[
|
||||
'general' => [
|
||||
'PHP_VERSION' => PHP_VERSION,
|
||||
'PHP_OS' => PHP_OS,
|
||||
'PHP_SAPI' => PHP_SAPI,
|
||||
'Peak Memory Usage' => GeneralUtility::formatSize(memory_get_peak_usage()),
|
||||
],
|
||||
'loadedExtensions' => implode(', ', get_loaded_extensions()),
|
||||
'constants' => get_defined_constants(true),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getContent(ModuleData $data): string
|
||||
{
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Modules/Info/PhpInfo.html';
|
||||
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
|
||||
$view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
|
||||
|
||||
$view->assignMultiple($data->getArrayCopy());
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Modules\Info;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\AbstractSubModule;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\DataProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleData;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
|
||||
/**
|
||||
* RequestInformation submodule of the admin panel
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class RequestInformation extends AbstractSubModule implements DataProviderInterface
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return 'info-request';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getLabel(): string
|
||||
{
|
||||
return $this->getLanguageService()->sL(
|
||||
'LLL:EXT:adminpanel/Resources/Private/Language/locallang_info.xlf:sub.request.label'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getDataToStore(ServerRequestInterface $request): ModuleData
|
||||
{
|
||||
return new ModuleData(
|
||||
[
|
||||
'post' => $_POST,
|
||||
'get' => $_GET,
|
||||
'cookie' => $_COOKIE,
|
||||
'session' => $_SESSION,
|
||||
'server' => $_SERVER,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getContent(ModuleData $data): string
|
||||
{
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Modules/Info/RequestInformation.html';
|
||||
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
|
||||
$view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
|
||||
|
||||
$view->assignMultiple($data->getArrayCopy());
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Modules;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\AbstractModule;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ShortInfoProviderInterface;
|
||||
use TYPO3\CMS\Core\TimeTracker\TimeTracker;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Admin Panel Info Module
|
||||
*/
|
||||
class InfoModule extends AbstractModule implements ShortInfoProviderInterface
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIconIdentifier(): string
|
||||
{
|
||||
return 'actions-document-info';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return 'info';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getLabel(): string
|
||||
{
|
||||
return $this->getLanguageService()->sL(
|
||||
'LLL:EXT:adminpanel/Resources/Private/Language/locallang_info.xlf:module.label'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getShortInfo(): string
|
||||
{
|
||||
$parseTime = $this->getTimeTracker()->getParseTime();
|
||||
return sprintf($this->getLanguageService()->sL(
|
||||
'LLL:EXT:adminpanel/Resources/Private/Language/locallang_info.xlf:module.shortinfo'
|
||||
), $parseTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TimeTracker
|
||||
*/
|
||||
protected function getTimeTracker(): TimeTracker
|
||||
{
|
||||
return GeneralUtility::makeInstance(TimeTracker::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Modules;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\AbstractModule;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\InitializableInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\PageSettingsProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ResourceProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\Repositories\FrontendGroupsRepository;
|
||||
use TYPO3\CMS\Core\Context\Context;
|
||||
use TYPO3\CMS\Core\Context\DateTimeAspect;
|
||||
use TYPO3\CMS\Core\Context\UserAspect;
|
||||
use TYPO3\CMS\Core\Context\VisibilityAspect;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
|
||||
/**
|
||||
* Admin Panel Preview Module
|
||||
*/
|
||||
class PreviewModule extends AbstractModule implements InitializableInterface, PageSettingsProviderInterface, ResourceProviderInterface
|
||||
{
|
||||
/**
|
||||
* module configuration, set on initialize
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIconIdentifier(): string
|
||||
{
|
||||
return 'actions-preview';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return 'preview';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getLabel(): string
|
||||
{
|
||||
return $this->getLanguageService()->sL(
|
||||
'LLL:EXT:adminpanel/Resources/Private/Language/locallang_preview.xlf:module.label'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function initializeModule(ServerRequestInterface $request): void
|
||||
{
|
||||
// Backend preview params (ADMCMD_) take precedence over configured admin panel values
|
||||
$simulateGroupByRequest = (int)($request->getQueryParams()['ADMCMD_simUser'] ?? 0);
|
||||
$simulateTimeByRequest = (int)($request->getQueryParams()['ADMCMD_simTime'] ?? 0);
|
||||
$this->config = [
|
||||
'showHiddenPages' => (bool)$this->getConfigOptionForModule('showHiddenPages'),
|
||||
'simulateDate' => $simulateTimeByRequest ?: (int)$this->getConfigOptionForModule('simulateDate'),
|
||||
'showHiddenRecords' => (bool)$this->getConfigOptionForModule('showHiddenRecords'),
|
||||
'simulateUserGroup' => $simulateGroupByRequest ?: (int)$this->getConfigOptionForModule('simulateUserGroup'),
|
||||
'showFluidDebug' => (bool)$this->getConfigOptionForModule('showFluidDebug'),
|
||||
];
|
||||
if ($this->config['showFluidDebug']) {
|
||||
// forcibly unset fluid caching as it does not care about the tsfe based caching settings
|
||||
unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['fluid_template']['frontend']);
|
||||
$GLOBALS['TSFE']->set_no_cache('Cache is disabled if fluid debugging is enabled', true);
|
||||
}
|
||||
$this->initializeFrontendPreview(
|
||||
$this->config['showHiddenPages'],
|
||||
$this->config['showHiddenRecords'],
|
||||
$this->config['simulateDate'],
|
||||
$this->config['simulateUserGroup']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getPageSettings(): string
|
||||
{
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Modules/Settings/Preview.html';
|
||||
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
|
||||
$view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
|
||||
|
||||
$frontendGroupsRepository = GeneralUtility::makeInstance(FrontendGroupsRepository::class);
|
||||
|
||||
$view->assignMultiple(
|
||||
[
|
||||
'show' => [
|
||||
'pageId' => (int)$this->getTypoScriptFrontendController()->id,
|
||||
'hiddenPages' => $this->config['showHiddenPages'],
|
||||
'hiddenRecords' => $this->config['showHiddenRecords'],
|
||||
'fluidDebug' => $this->config['showFluidDebug'],
|
||||
],
|
||||
'simulateDate' => $this->config['simulateDate'],
|
||||
'frontendUserGroups' => [
|
||||
'availableGroups' => $frontendGroupsRepository->getAvailableFrontendUserGroups(),
|
||||
'selected' => (int)$this->config['simulateUserGroup'],
|
||||
],
|
||||
]
|
||||
);
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $option
|
||||
* @return string
|
||||
*/
|
||||
protected function getConfigOptionForModule(string $option): string
|
||||
{
|
||||
return $this->configurationService->getConfigurationOption(
|
||||
'preview',
|
||||
$option
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TypoScriptFrontendController
|
||||
*/
|
||||
protected function getTypoScriptFrontendController(): TypoScriptFrontendController
|
||||
{
|
||||
return $GLOBALS['TSFE'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize frontend preview functionality incl.
|
||||
* simulation of users or time
|
||||
*
|
||||
* @param bool $showHiddenPages
|
||||
* @param bool $showHiddenRecords
|
||||
* @param int $simulateDate
|
||||
* @param int $simulateUserGroup UID of the fe_group to simulate
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function initializeFrontendPreview(
|
||||
bool $showHiddenPages,
|
||||
bool $showHiddenRecords,
|
||||
int $simulateDate,
|
||||
int $simulateUserGroup
|
||||
): void {
|
||||
$context = GeneralUtility::makeInstance(Context::class);
|
||||
$typoScriptFrontendController = $this->getTypoScriptFrontendController();
|
||||
$typoScriptFrontendController->clear_preview();
|
||||
$typoScriptFrontendController->fePreview = 1;
|
||||
|
||||
// Modify visibility settings (hidden pages + hidden content)
|
||||
$context->setAspect(
|
||||
'visibility',
|
||||
GeneralUtility::makeInstance(VisibilityAspect::class, $showHiddenPages, $showHiddenRecords)
|
||||
);
|
||||
|
||||
// Simulate date
|
||||
$simTime = null;
|
||||
if ($simulateDate) {
|
||||
$simTime = $this->parseDate($simulateDate);
|
||||
if ($simTime) {
|
||||
$GLOBALS['SIM_EXEC_TIME'] = $simTime;
|
||||
$GLOBALS['SIM_ACCESS_TIME'] = $simTime - $simTime % 60;
|
||||
$context->setAspect(
|
||||
'date',
|
||||
GeneralUtility::makeInstance(
|
||||
DateTimeAspect::class,
|
||||
new \DateTimeImmutable('@' . $GLOBALS['SIM_EXEC_TIME'])
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
// simulate usergroup
|
||||
if ($simulateUserGroup) {
|
||||
$typoScriptFrontendController->simUserGroup = $simulateUserGroup;
|
||||
if (!$typoScriptFrontendController->fe_user instanceof FrontendUserAuthentication) {
|
||||
$typoScriptFrontendController->fe_user = GeneralUtility::makeInstance(
|
||||
FrontendUserAuthentication::class
|
||||
);
|
||||
}
|
||||
if (!is_array($typoScriptFrontendController->fe_user->user)) {
|
||||
// This can be removed once #90989 is fixed
|
||||
$typoScriptFrontendController->fe_user->user = ['uid' => PHP_INT_MAX];
|
||||
}
|
||||
$typoScriptFrontendController->fe_user->user[$typoScriptFrontendController->fe_user->usergroup_column] = $simulateUserGroup;
|
||||
$context->setAspect(
|
||||
'frontend.user',
|
||||
GeneralUtility::makeInstance(
|
||||
UserAspect::class,
|
||||
$typoScriptFrontendController->fe_user ?: null,
|
||||
[$simulateUserGroup]
|
||||
)
|
||||
);
|
||||
}
|
||||
if (!$simulateUserGroup && !$simTime && !$showHiddenPages && !$showHiddenRecords) {
|
||||
$typoScriptFrontendController->fePreview = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getJavaScriptFiles(): array
|
||||
{
|
||||
return ['EXT:adminpanel/Resources/Public/JavaScript/Modules/Preview.js'];
|
||||
}
|
||||
|
||||
/**
|
||||
* The simulated date needs to be a timestring (UTC)
|
||||
*
|
||||
* Simulation date is either set via configuration of AdminPanel (Date and Time Fields) or via ADMCMD_ $_GET
|
||||
* parameter from backend previews
|
||||
*
|
||||
* @param int $simulateDate
|
||||
* @return int
|
||||
*/
|
||||
protected function parseDate(int $simulateDate): ?int
|
||||
{
|
||||
try {
|
||||
$simTime = (new \DateTime('@' . $simulateDate))->getTimestamp();
|
||||
$simTime = max($simTime, 60);
|
||||
} catch (\Exception $e) {
|
||||
$simTime = null;
|
||||
}
|
||||
return $simTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string array with css files that will be rendered after the module
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCssFiles(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Modules\TsDebug;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\AbstractSubModule;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\InitializableInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleData;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleSettingsProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\Service\ConfigurationService;
|
||||
use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\TimeTracker\TimeTracker;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
|
||||
/**
|
||||
* Class TypoScriptWaterfall
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class TypoScriptWaterfall extends AbstractSubModule implements InitializableInterface, ModuleSettingsProviderInterface
|
||||
{
|
||||
/**
|
||||
* @var ConfigurationService
|
||||
*/
|
||||
protected $configurationService;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return 'typoscript-waterfall';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getLabel(): string
|
||||
{
|
||||
return $this->getLanguageService()->sL(
|
||||
'LLL:EXT:adminpanel/Resources/Private/Language/locallang_tsdebug.xlf:sub.waterfall.label'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function initializeModule(ServerRequestInterface $request): void
|
||||
{
|
||||
$typoScriptFrontend = $this->getTypoScriptFrontendController();
|
||||
$typoScriptFrontend->forceTemplateParsing = $this->getConfigurationOption(
|
||||
'forceTemplateParsing'
|
||||
);
|
||||
if ($typoScriptFrontend->forceTemplateParsing) {
|
||||
$typoScriptFrontend->set_no_cache('Admin Panel: Force template parsing', true);
|
||||
}
|
||||
$this->getTimeTracker()->LR = (bool)$this->getConfigurationOption('LR');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the content for the "tsdebug" section ("module") of the Admin Panel
|
||||
*
|
||||
* @param ModuleData $data
|
||||
* @return string HTML
|
||||
*/
|
||||
public function getContent(ModuleData $data): string
|
||||
{
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Modules/TsDebug/TypoScript.html';
|
||||
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
|
||||
$view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
|
||||
|
||||
$view->assignMultiple(
|
||||
[
|
||||
'tree' => (int)$this->getConfigurationOption('tree'),
|
||||
'display' => [
|
||||
'times' => (int)$this->getConfigurationOption('displayTimes'),
|
||||
'messages' => (int)$this->getConfigurationOption('displayMessages'),
|
||||
'content' => (int)$this->getConfigurationOption('displayContent'),
|
||||
],
|
||||
'trackContentRendering' => (int)$this->getConfigurationOption('LR'),
|
||||
'forceTemplateParsing' => (int)$this->getConfigurationOption('forceTemplateParsing'),
|
||||
'typoScriptLog' => $this->renderTypoScriptLog(),
|
||||
]
|
||||
);
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getSettings(): string
|
||||
{
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$templateNameAndPath = 'EXT:adminpanel/Resources/Private/Templates/Modules/TsDebug/TypoScriptSettings.html';
|
||||
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templateNameAndPath));
|
||||
$view->setPartialRootPaths(['EXT:adminpanel/Resources/Private/Partials']);
|
||||
|
||||
$view->assignMultiple(
|
||||
[
|
||||
'tree' => (int)$this->getConfigurationOption('tree'),
|
||||
'display' => [
|
||||
'times' => (int)$this->getConfigurationOption('displayTimes'),
|
||||
'messages' => (int)$this->getConfigurationOption('displayMessages'),
|
||||
'content' => (int)$this->getConfigurationOption('displayContent'),
|
||||
],
|
||||
'trackContentRendering' => (int)$this->getConfigurationOption('LR'),
|
||||
'forceTemplateParsing' => (int)$this->getConfigurationOption('forceTemplateParsing')
|
||||
]
|
||||
);
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current BE user.
|
||||
*
|
||||
* @return BackendUserAuthentication|FrontendBackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUser(): BackendUserAuthentication
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $option
|
||||
* @return bool
|
||||
*/
|
||||
protected function getConfigurationOption(string $option): bool
|
||||
{
|
||||
return (bool)$this->configurationService->getConfigurationOption('tsdebug', $option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the TypoScript log as string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function renderTypoScriptLog(): string
|
||||
{
|
||||
$timeTracker = $this->getTimeTracker();
|
||||
$timeTracker->printConf['flag_tree'] = $this->getConfigurationOption('tree');
|
||||
$timeTracker->printConf['allTime'] = $this->getConfigurationOption(
|
||||
'displayTimes'
|
||||
);
|
||||
$timeTracker->printConf['flag_messages'] = $this->getConfigurationOption(
|
||||
'displayMessages'
|
||||
);
|
||||
$timeTracker->printConf['flag_content'] = $this->getConfigurationOption(
|
||||
'displayContent'
|
||||
);
|
||||
return $timeTracker->printTSlog();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TimeTracker
|
||||
*/
|
||||
protected function getTimeTracker(): TimeTracker
|
||||
{
|
||||
return GeneralUtility::makeInstance(TimeTracker::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TypoScriptFrontendController
|
||||
*/
|
||||
protected function getTypoScriptFrontendController(): TypoScriptFrontendController
|
||||
{
|
||||
return $GLOBALS['TSFE'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Modules;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\AbstractModule;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ShortInfoProviderInterface;
|
||||
use TYPO3\CMS\Core\TimeTracker\TimeTracker;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Admin Panel TypoScript Debug Module
|
||||
*/
|
||||
class TsDebugModule extends AbstractModule implements ShortInfoProviderInterface
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return 'tsdebug';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getIconIdentifier(): string
|
||||
{
|
||||
return 'mimetypes-x-content-template-static';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getLabel(): string
|
||||
{
|
||||
return $this->getLanguageService()->sL(
|
||||
'LLL:EXT:adminpanel/Resources/Private/Language/locallang_tsdebug.xlf:module.label'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getShortInfo(): string
|
||||
{
|
||||
$messageCount = 0;
|
||||
foreach ($this->getTimeTracker()->tsStackLog as $log) {
|
||||
$messageCount += count($log['message'] ?? []);
|
||||
}
|
||||
return sprintf(
|
||||
$this->getLanguageService()->sL(
|
||||
'LLL:EXT:adminpanel/Resources/Private/Language/locallang_tsdebug.xlf:module.shortinfo'
|
||||
),
|
||||
$messageCount
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TimeTracker
|
||||
*/
|
||||
protected function getTimeTracker(): TimeTracker
|
||||
{
|
||||
return GeneralUtility::makeInstance(TimeTracker::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Repositories;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
|
||||
use TYPO3\CMS\Core\Type\Bitmask\Permission;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Admin Panel Frontend Groups Repository
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class FrontendGroupsRepository
|
||||
{
|
||||
/**
|
||||
* returns an array of all available frontend user groups including hidden ones.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAvailableFrontendUserGroups(): array
|
||||
{
|
||||
$optionCount = $this->getUserGroupOptionCountByBackendUser($this->getBackendUser());
|
||||
|
||||
$frontendGroups = [];
|
||||
if ($optionCount > 0) {
|
||||
$frontendGroups = $this->getUserGroupsForPagesByBackendUser($this->getBackendUser());
|
||||
}
|
||||
|
||||
return $frontendGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* fetches the amount of user groups
|
||||
*
|
||||
* @param FrontendBackendUserAuthentication $beUser
|
||||
* @return int
|
||||
*/
|
||||
protected function getUserGroupOptionCountByBackendUser(FrontendBackendUserAuthentication $beUser): int
|
||||
{
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('fe_groups');
|
||||
|
||||
$queryBuilder->getRestrictions()
|
||||
->removeAll()
|
||||
->add(GeneralUtility::makeInstance(DeletedRestriction::class));
|
||||
|
||||
$optionCount = $queryBuilder->count('fe_groups.uid')
|
||||
->from('fe_groups', 'fe_groups')
|
||||
->innerJoin(
|
||||
'fe_groups',
|
||||
'pages',
|
||||
'pages',
|
||||
$queryBuilder->expr()->eq('pages.uid', $queryBuilder->quoteIdentifier('fe_groups.pid'))
|
||||
)
|
||||
->where(
|
||||
$beUser->getPagePermsClause(Permission::PAGE_SHOW)
|
||||
)
|
||||
->execute()
|
||||
->fetchColumn(0);
|
||||
|
||||
return (int)$optionCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* fetches all frontend user groups, except deleted, for pages
|
||||
*
|
||||
* @param FrontendBackendUserAuthentication $beUser
|
||||
* @return array
|
||||
*/
|
||||
protected function getUserGroupsForPagesByBackendUser(FrontendBackendUserAuthentication $beUser): array
|
||||
{
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('fe_groups');
|
||||
|
||||
$queryBuilder->getRestrictions()
|
||||
->removeAll()
|
||||
->add(GeneralUtility::makeInstance(DeletedRestriction::class));
|
||||
|
||||
return $queryBuilder->select('fe_groups.uid', 'fe_groups.title')
|
||||
->from('fe_groups')
|
||||
->innerJoin(
|
||||
'fe_groups',
|
||||
'pages',
|
||||
'pages',
|
||||
$queryBuilder->expr()->eq('pages.uid', $queryBuilder->quoteIdentifier('fe_groups.pid'))
|
||||
)
|
||||
->where(
|
||||
$beUser->getPagePermsClause(Permission::PAGE_SHOW)
|
||||
)
|
||||
->orderBy('fe_groups.title')
|
||||
->execute()
|
||||
->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current BE user.
|
||||
*
|
||||
* @return FrontendBackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUser(): FrontendBackendUserAuthentication
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Service;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ConfigurableInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\OnSubmitActorInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\SubmoduleProviderInterface;
|
||||
use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
|
||||
/**
|
||||
* Admin Panel Service Class for Configuration Handling
|
||||
*
|
||||
* Scope: User TSConfig + Backend User UC
|
||||
*/
|
||||
class ConfigurationService implements SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $mainConfiguration;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->mainConfiguration = $this->getBackendUser()->getTSConfig()['admPanel.'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MainConfiguration (User TSConfig admPanel)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMainConfiguration(): array
|
||||
{
|
||||
return $this->mainConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to return configuration options
|
||||
* Checks User TSConfig overrides and current backend user session
|
||||
*
|
||||
* @param string $identifier
|
||||
* @param string $option
|
||||
* @return string
|
||||
*/
|
||||
public function getConfigurationOption(string $identifier, string $option): string
|
||||
{
|
||||
if ($identifier === '' || $option === '') {
|
||||
throw new \InvalidArgumentException('Identifier and option may not be empty', 1532861423);
|
||||
}
|
||||
|
||||
if (isset($this->mainConfiguration['override.'][$identifier . '.'][$option])) {
|
||||
$returnValue = $this->mainConfiguration['override.'][$identifier . '.'][$option];
|
||||
} else {
|
||||
$returnValue = $this->getBackendUser()->uc['AdminPanel'][$identifier . '_' . $option] ?? '';
|
||||
}
|
||||
|
||||
return (string)$returnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save admin panel configuration to backend user UC
|
||||
* triggers onSubmit method of modules to enable each module
|
||||
* to enhance the save action
|
||||
*
|
||||
* @param \TYPO3\CMS\Adminpanel\ModuleApi\ModuleInterface[] $modules
|
||||
* @param ServerRequestInterface $request
|
||||
*/
|
||||
public function saveConfiguration(array $modules, ServerRequestInterface $request): void
|
||||
{
|
||||
$configurationToSave = $request->getParsedBody()['TSFE_ADMIN_PANEL'] ?? [];
|
||||
$beUser = $this->getBackendUser();
|
||||
$this->triggerOnSubmitActors($modules, $request, $configurationToSave);
|
||||
|
||||
$existingConfiguration = $beUser->uc['AdminPanel'] ?? [];
|
||||
$existingConfiguration = is_array($existingConfiguration) ? $existingConfiguration : [];
|
||||
|
||||
// Settings
|
||||
$beUser->uc['AdminPanel'] = array_merge($existingConfiguration, $configurationToSave);
|
||||
unset($beUser->uc['AdminPanel']['action']);
|
||||
// Saving
|
||||
$beUser->writeUC();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current BE user.
|
||||
*
|
||||
* @return BackendUserAuthentication|FrontendBackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUser(): BackendUserAuthentication
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $modules
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param $configurationToSave
|
||||
*/
|
||||
protected function triggerOnSubmitActors(
|
||||
array $modules,
|
||||
ServerRequestInterface $request,
|
||||
$configurationToSave
|
||||
): void {
|
||||
foreach ($modules as $module) {
|
||||
if (
|
||||
$module instanceof OnSubmitActorInterface
|
||||
&& (
|
||||
($module instanceof ConfigurableInterface && $module->isEnabled())
|
||||
|| !($module instanceof ConfigurableInterface)
|
||||
)
|
||||
) {
|
||||
$module->onSubmit($configurationToSave, $request);
|
||||
}
|
||||
if ($module instanceof SubmoduleProviderInterface) {
|
||||
$this->triggerOnSubmitActors($module->getSubModules(), $request, $configurationToSave);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Service;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
|
||||
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Core\Context\Context;
|
||||
use TYPO3\CMS\Core\Context\LanguageAspect;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
|
||||
use TYPO3\CMS\Core\Imaging\Icon;
|
||||
use TYPO3\CMS\Core\Imaging\IconFactory;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Type\Bitmask\Permission;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
|
||||
/**
|
||||
* Class for the Edit Toolbar
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class EditToolbarService
|
||||
{
|
||||
|
||||
/**
|
||||
* Creates the tool bar links for the "edit" section of the Admin Panel.
|
||||
*
|
||||
* @return string A string containing images wrapped in <a>-tags linking them to proper functions.
|
||||
*/
|
||||
public function createToolbar(): string
|
||||
{
|
||||
/** @var LanguageAspect $languageAspect */
|
||||
$languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language');
|
||||
$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
|
||||
$tsfe = $this->getTypoScriptFrontendController();
|
||||
// If mod.newContentElementWizard.override is set, use that extension's create new content wizard instead:
|
||||
$moduleName = BackendUtility::getPagesTSconfig($tsfe->page['uid'])['mod.']['newContentElementWizard.']['override'] ?? 'new_content_element';
|
||||
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
|
||||
$perms = $this->getBackendUser()->calcPerms($tsfe->page);
|
||||
$langAllowed = $this->getBackendUser()->checkLanguageAccess($languageAspect->getId());
|
||||
$id = $tsfe->id;
|
||||
$returnUrl = GeneralUtility::getIndpEnv('REQUEST_URI');
|
||||
$classes = 'typo3-adminPanel-btn typo3-adminPanel-btn-default';
|
||||
$output = [];
|
||||
$output[] = '<div class="typo3-adminPanel-form-group">';
|
||||
$output[] = ' <div class="typo3-adminPanel-btn-group" role="group">';
|
||||
|
||||
// History
|
||||
$link = (string)$uriBuilder->buildUriFromRoute(
|
||||
'record_history',
|
||||
[
|
||||
'element' => 'pages:' . $id,
|
||||
'returnUrl' => $returnUrl,
|
||||
]
|
||||
);
|
||||
$title = $this->getLabel('edit_recordHistory');
|
||||
$output[] = '<a class="' .
|
||||
$classes .
|
||||
'" href="' .
|
||||
htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
|
||||
'#latest" title="' .
|
||||
$title .
|
||||
'">';
|
||||
$output[] = ' ' . $iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL)->render();
|
||||
$output[] = '</a>';
|
||||
|
||||
// New Content
|
||||
if ($perms & Permission::CONTENT_EDIT && $langAllowed) {
|
||||
$linkParameters = [
|
||||
'id' => $id,
|
||||
'returnUrl' => $returnUrl,
|
||||
];
|
||||
if (!empty($languageAspect->getId())) {
|
||||
$linkParameters['sys_language_uid'] = $languageAspect->getId();
|
||||
}
|
||||
$link = (string)$uriBuilder->buildUriFromRoute($moduleName, $linkParameters);
|
||||
$icon = $iconFactory->getIcon('actions-add', Icon::SIZE_SMALL)->render();
|
||||
$title = $this->getLabel('edit_newContentElement');
|
||||
$output[] = '<a class="' .
|
||||
$classes .
|
||||
'" href="' .
|
||||
htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
|
||||
'" title="' .
|
||||
$title .
|
||||
'">';
|
||||
$output[] = ' ' . $icon;
|
||||
$output[] = '</a>';
|
||||
}
|
||||
|
||||
// Move Page
|
||||
if ($perms & Permission::PAGE_EDIT) {
|
||||
$link = (string)$uriBuilder->buildUriFromRoute(
|
||||
'move_element',
|
||||
[
|
||||
'table' => 'pages',
|
||||
'uid' => $id,
|
||||
'returnUrl' => $returnUrl,
|
||||
]
|
||||
);
|
||||
$icon = $iconFactory->getIcon('actions-document-move', Icon::SIZE_SMALL)->render();
|
||||
$title = $this->getLabel('edit_move_page');
|
||||
$output[] = '<a class="' .
|
||||
$classes .
|
||||
'" href="' .
|
||||
htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
|
||||
'" title="' .
|
||||
$title .
|
||||
'">';
|
||||
$output[] = ' ' . $icon;
|
||||
$output[] = '</a>';
|
||||
}
|
||||
|
||||
// New Page
|
||||
if ($perms & Permission::PAGE_NEW) {
|
||||
$link = (string)$uriBuilder->buildUriFromRoute(
|
||||
'db_new',
|
||||
[
|
||||
'id' => $id,
|
||||
'pagesOnly' => 1,
|
||||
'returnUrl' => $returnUrl,
|
||||
]
|
||||
);
|
||||
$icon = $iconFactory->getIcon('actions-page-new', Icon::SIZE_SMALL)->render();
|
||||
$title = $this->getLabel('edit_newPage');
|
||||
$output[] = '<a class="' .
|
||||
$classes .
|
||||
'" href="' .
|
||||
htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
|
||||
'" title="' .
|
||||
$title .
|
||||
'">';
|
||||
$output[] = ' ' . $icon;
|
||||
$output[] = '</a>';
|
||||
}
|
||||
|
||||
// Edit Page
|
||||
if ($perms & Permission::PAGE_EDIT) {
|
||||
$link = (string)$uriBuilder->buildUriFromRoute(
|
||||
'record_edit',
|
||||
[
|
||||
'edit[pages][' . $id . ']' => 'edit',
|
||||
'noView' => 1,
|
||||
'returnUrl' => $returnUrl,
|
||||
]
|
||||
);
|
||||
$icon = $iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)->render();
|
||||
$title = $this->getLabel('edit_editPageProperties');
|
||||
$output[] = '<a class="' .
|
||||
$classes .
|
||||
'" href="' .
|
||||
htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
|
||||
'" title="' .
|
||||
$title .
|
||||
'">';
|
||||
$output[] = ' ' . $icon;
|
||||
$output[] = '</a>';
|
||||
}
|
||||
|
||||
// Edit Page Overlay
|
||||
if ($perms & Permission::PAGE_EDIT && $languageAspect->getId() > 0 && $langAllowed) {
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('pages');
|
||||
$queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
|
||||
$row = $queryBuilder
|
||||
->select('uid', 'pid', 't3ver_state')
|
||||
->from('pages')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq(
|
||||
$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
|
||||
$queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
|
||||
),
|
||||
$queryBuilder->expr()->eq(
|
||||
$GLOBALS['TCA']['pages']['ctrl']['languageField'],
|
||||
$queryBuilder->createNamedParameter($languageAspect->getId(), \PDO::PARAM_INT)
|
||||
)
|
||||
)
|
||||
->setMaxResults(1)
|
||||
->execute()
|
||||
->fetch();
|
||||
$tsfe->sys_page->versionOL('pages', $row);
|
||||
if (is_array($row)) {
|
||||
$link = (string)$uriBuilder->buildUriFromRoute(
|
||||
'record_edit',
|
||||
[
|
||||
'edit[pages][' . $row['uid'] . ']' => 'edit',
|
||||
'noView' => 1,
|
||||
'returnUrl' => $returnUrl,
|
||||
]
|
||||
);
|
||||
$icon = $iconFactory->getIcon('mimetypes-x-content-page-language-overlay', Icon::SIZE_SMALL)
|
||||
->render();
|
||||
$title = $this->getLabel('edit_editPageOverlay');
|
||||
$output[] = '<a class="' .
|
||||
$classes .
|
||||
'" href="' .
|
||||
htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
|
||||
'" title="' .
|
||||
$title .
|
||||
'">';
|
||||
$output[] = ' ' . $icon;
|
||||
$output[] = '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
// Open list view
|
||||
if ($this->getBackendUser()->check('modules', 'web_list')) {
|
||||
$link = (string)$uriBuilder->buildUriFromRoute(
|
||||
'web_list',
|
||||
[
|
||||
'id' => $id,
|
||||
'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI'),
|
||||
]
|
||||
);
|
||||
$icon = $iconFactory->getIcon('actions-system-list-open', Icon::SIZE_SMALL)->render();
|
||||
$title = $this->getLabel('edit_db_list');
|
||||
$output[] = '<a class="' .
|
||||
$classes .
|
||||
'" href="' .
|
||||
htmlspecialchars($link, ENT_QUOTES | ENT_HTML5) .
|
||||
'" title="' .
|
||||
$title .
|
||||
'">';
|
||||
$output[] = ' ' . $icon;
|
||||
$output[] = '</a>';
|
||||
}
|
||||
|
||||
$output[] = ' </div>';
|
||||
$output[] = '</div>';
|
||||
return implode('', $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate given key
|
||||
*
|
||||
* @param string $key Key for a label in the $LOCAL_LANG array of "sysext/core/Resources/Private/Language/locallang_tsfe.xlf
|
||||
* @return string The value for the $key
|
||||
*/
|
||||
protected function getLabel($key): ?string
|
||||
{
|
||||
return htmlspecialchars($this->getLanguageService()->getLL($key), ENT_QUOTES | ENT_HTML5);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FrontendBackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUser(): FrontendBackendUserAuthentication
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LanguageService
|
||||
*/
|
||||
protected function getLanguageService(): LanguageService
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TypoScriptFrontendController
|
||||
*/
|
||||
protected function getTypoScriptFrontendController(): TypoScriptFrontendController
|
||||
{
|
||||
return $GLOBALS['TSFE'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Service;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Adminpanel\Exceptions\InvalidConfigurationException;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ConfigurableInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\SubmoduleProviderInterface;
|
||||
use TYPO3\CMS\Core\Service\DependencyOrderingService;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Admin Panel Module Loader
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ModuleLoader
|
||||
{
|
||||
|
||||
/**
|
||||
* Validates, sorts and initiates the registered modules
|
||||
*
|
||||
* @param array $modules
|
||||
* @return \TYPO3\CMS\Adminpanel\ModuleApi\ModuleInterface[]
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function validateSortAndInitializeModules(array $modules): array
|
||||
{
|
||||
if (empty($modules)) {
|
||||
return [];
|
||||
}
|
||||
foreach ($modules as $identifier => $configuration) {
|
||||
if (empty($configuration) || !is_array($configuration)) {
|
||||
throw new InvalidConfigurationException(
|
||||
'Missing configuration for module "' . $identifier . '".',
|
||||
1519490105
|
||||
);
|
||||
}
|
||||
if (!is_string($configuration['module']) ||
|
||||
empty($configuration['module']) ||
|
||||
!class_exists($configuration['module']) ||
|
||||
!is_subclass_of(
|
||||
$configuration['module'],
|
||||
ModuleInterface::class,
|
||||
true
|
||||
)
|
||||
) {
|
||||
throw new InvalidConfigurationException(
|
||||
'The module "' .
|
||||
$identifier .
|
||||
'" defines an invalid module class. Ensure the class exists and implements the "' .
|
||||
ModuleInterface::class .
|
||||
'".',
|
||||
1519490112
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$orderedModules = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies(
|
||||
$modules
|
||||
);
|
||||
|
||||
$moduleInstances = [];
|
||||
foreach ($orderedModules as $moduleConfiguration) {
|
||||
$module = GeneralUtility::makeInstance($moduleConfiguration['module']);
|
||||
if (
|
||||
$module instanceof ModuleInterface
|
||||
&& (
|
||||
($module instanceof ConfigurableInterface && $module->isEnabled())
|
||||
|| !($module instanceof ConfigurableInterface)
|
||||
)
|
||||
) {
|
||||
$moduleInstances[$module->getIdentifier()] = $module;
|
||||
}
|
||||
if ($module instanceof SubmoduleProviderInterface) {
|
||||
$subModuleInstances = $this->validateSortAndInitializeModules($moduleConfiguration['submodules'] ?? []);
|
||||
$module->setSubModules($subModuleInstances);
|
||||
}
|
||||
}
|
||||
return $moduleInstances;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Utility;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Helper class to keep track of memory consumption in loggers to reduce risk of running out of memory
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class MemoryUtility
|
||||
{
|
||||
private const MINIMAL_PERCENT_OF_FREE_MEMORY = 0.30;
|
||||
|
||||
/**
|
||||
* Checks memory usage used in current process - this is no guarantee for not running out of memory
|
||||
* but should prevent memory exhaustion due to the admin panel in most cases.
|
||||
* The loggers will stop logging once the amount of free memory falls below the threshold (see
|
||||
* MINIMAL_PERCENT_OF_FREE_MEMORY const).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isMemoryConsumptionTooHigh(): bool
|
||||
{
|
||||
$iniLimit = ini_get('memory_limit');
|
||||
$memoryLimit = $iniLimit === '-1' ? -1 : GeneralUtility::getBytesFromSizeMeasurement($iniLimit);
|
||||
$freeMemory = $memoryLimit - memory_get_usage(true);
|
||||
|
||||
return $memoryLimit > 0 && $freeMemory < (self::MINIMAL_PERCENT_OF_FREE_MEMORY * $memoryLimit);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Utility;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ResourceProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\SubmoduleProviderInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
|
||||
class ResourceUtility
|
||||
{
|
||||
/**
|
||||
* Get additional resources (css, js) from modules and merge it to
|
||||
* one array - returns an array of full html tags
|
||||
*
|
||||
* @param \TYPO3\CMS\Adminpanel\ModuleApi\ResourceProviderInterface[] $modules
|
||||
* @return array
|
||||
*/
|
||||
public static function getAdditionalResourcesForModules(array $modules): array
|
||||
{
|
||||
$result = [
|
||||
'js' => '',
|
||||
'css' => '',
|
||||
];
|
||||
foreach ($modules as $module) {
|
||||
if ($module instanceof ResourceProviderInterface) {
|
||||
foreach ($module->getJavaScriptFiles() as $file) {
|
||||
$result['js'] .= static::getJsTag($file);
|
||||
}
|
||||
foreach ($module->getCssFiles() as $file) {
|
||||
$result['css'] .= static::getCssTag($file);
|
||||
}
|
||||
}
|
||||
if ($module instanceof SubmoduleProviderInterface) {
|
||||
$subResult = self::getAdditionalResourcesForModules($module->getSubModules());
|
||||
$result['js'] .= $subResult['js'];
|
||||
$result['css'] .= $subResult['css'];
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function getAdditionalResourcesForModule(ResourceProviderInterface $module): array
|
||||
{
|
||||
$result = [
|
||||
'js' => '',
|
||||
'css' => '',
|
||||
];
|
||||
foreach ($module->getJavaScriptFiles() as $file) {
|
||||
$result['js'] .= static::getJsTag($file);
|
||||
}
|
||||
foreach ($module->getCssFiles() as $file) {
|
||||
$result['css'] .= static::getCssTag($file);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a link tag with the admin panel stylesheet
|
||||
* defined using TBE_STYLES
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getAdminPanelStylesheet(): string
|
||||
{
|
||||
$result = '';
|
||||
if (!empty($GLOBALS['TBE_STYLES']['stylesheets']['admPanel'])) {
|
||||
$stylesheet = GeneralUtility::locationHeaderUrl($GLOBALS['TBE_STYLES']['stylesheets']['admPanel']);
|
||||
$result = '<link rel="stylesheet" type="text/css" href="' .
|
||||
htmlspecialchars($stylesheet, ENT_QUOTES | ENT_HTML5) . '" />';
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a css tag for file - with absolute web path resolving
|
||||
*
|
||||
* @param string $cssFileLocation
|
||||
* @return string
|
||||
*/
|
||||
protected static function getCssTag(string $cssFileLocation): string
|
||||
{
|
||||
$css = '<link type="text/css" rel="stylesheet" href="' .
|
||||
htmlspecialchars(
|
||||
PathUtility::getAbsoluteWebPath(GeneralUtility::getFileAbsFileName($cssFileLocation)),
|
||||
ENT_QUOTES | ENT_HTML5
|
||||
) .
|
||||
'" media="all" />';
|
||||
return $css;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a script tag for JavaScript with absolute paths
|
||||
*
|
||||
* @param string $jsFileLocation
|
||||
* @return string
|
||||
*/
|
||||
protected static function getJsTag(string $jsFileLocation): string
|
||||
{
|
||||
$js = '<script type="text/javascript" src="' .
|
||||
htmlspecialchars(
|
||||
PathUtility::getAbsoluteWebPath(GeneralUtility::getFileAbsFileName($jsFileLocation)),
|
||||
ENT_QUOTES | ENT_HTML5
|
||||
) .
|
||||
'"></script>';
|
||||
return $js;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string with tags for main admin panel resources
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getResources(): array
|
||||
{
|
||||
$jsFileLocation = 'EXT:adminpanel/Resources/Public/JavaScript/AdminPanel.js';
|
||||
$js = ResourceUtility::getJsTag($jsFileLocation);
|
||||
$cssFileLocation = 'EXT:adminpanel/Resources/Public/Css/adminpanel.css';
|
||||
$css = ResourceUtility::getCssTag($cssFileLocation);
|
||||
|
||||
return [
|
||||
'css' => $css . ResourceUtility::getAdminPanelStylesheet(),
|
||||
'js' => $js,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\Utility;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
|
||||
|
||||
/**
|
||||
* Helper class to check if the admin panel is enabled and active from outside
|
||||
*
|
||||
* Useful for initialization, checks in early hooks or middleware implementations
|
||||
*/
|
||||
class StateUtility
|
||||
{
|
||||
/**
|
||||
* Checks if adminPanel was configured to be shown
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isActivatedForUser(): bool
|
||||
{
|
||||
$beUser = $GLOBALS['BE_USER'] ?? null;
|
||||
if ($beUser instanceof FrontendBackendUserAuthentication) {
|
||||
$adminPanelConfiguration = $beUser->getTSConfig()['admPanel.'] ?? [];
|
||||
// set legacy config
|
||||
$beUser->extAdminConfig = $adminPanelConfiguration;
|
||||
if (isset($adminPanelConfiguration['enable.'])) {
|
||||
// only enabled if at least one module is enabled.
|
||||
return (bool)array_filter($adminPanelConfiguration['enable.']);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if admin panel was activated
|
||||
* (switched "on" via GUI)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isOpen(): bool
|
||||
{
|
||||
$beUser = $GLOBALS['BE_USER'] ?? null;
|
||||
return (bool)($beUser->uc['AdminPanel']['display_top'] ?? false);
|
||||
}
|
||||
|
||||
public static function isActivatedInTypoScript(): bool
|
||||
{
|
||||
return (bool)($GLOBALS['TSFE']->config['config']['admPanel'] ?? false);
|
||||
}
|
||||
|
||||
public static function isHiddenForUser(): bool
|
||||
{
|
||||
return (bool)($GLOBALS['BE_USER']->extAdminConfig['hide'] ?? false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,480 @@
|
||||
<?php
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\View;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ConfigurableInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\DataProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleInterface;
|
||||
use TYPO3\CMS\Adminpanel\Service\EditToolbarService;
|
||||
use TYPO3\CMS\Adminpanel\Utility\StateUtility;
|
||||
use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Cache\CacheManager;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
|
||||
/**
|
||||
* View class for the admin panel in frontend editing.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class AdminPanelView
|
||||
{
|
||||
/**
|
||||
* Force preview
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $ext_forcePreview = false;
|
||||
|
||||
/**
|
||||
* Array of adminPanel modules
|
||||
*
|
||||
* @var \TYPO3\CMS\Adminpanel\ModuleApi\ModuleInterface[]
|
||||
*/
|
||||
protected $modules = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $configuration;
|
||||
|
||||
/**
|
||||
* Setter for injecting new-style modules
|
||||
*
|
||||
* @see \TYPO3\CMS\Adminpanel\Controller\MainController::render()
|
||||
* @param array $modules
|
||||
* @internal
|
||||
*/
|
||||
public function setModules(array $modules): void
|
||||
{
|
||||
$this->modules = $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns LanguageService
|
||||
*
|
||||
* @return \TYPO3\CMS\Core\Localization\LanguageService
|
||||
*/
|
||||
protected function getLanguageService()
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current BE user.
|
||||
*
|
||||
* @return FrontendBackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUser()
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
* Admin Panel: Deprecated API
|
||||
****************************************************/
|
||||
|
||||
/**
|
||||
* Backwards compatibility method ensuring hook still gets the same content as before
|
||||
*
|
||||
* @deprecated since TYPO3 v9 - remove when hook can be removed
|
||||
* @internal
|
||||
* @return string
|
||||
* @throws \UnexpectedValueException
|
||||
*/
|
||||
public function callDeprecatedHookObject(): string
|
||||
{
|
||||
$moduleContent = '';
|
||||
if (StateUtility::isOpen()) {
|
||||
foreach ($this->modules as $module) {
|
||||
$moduleContent .= $this->getModule($module);
|
||||
}
|
||||
|
||||
foreach (
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_adminpanel.php']['extendAdminPanel']
|
||||
??
|
||||
[] as $className
|
||||
) {
|
||||
trigger_error(
|
||||
'The hook $GLOBALS[TYPO3_CONF_VARS][SC_OPTIONS][tslib/class.tslib_adminpanel.php][extendAdminPanel] will be removed in TYPO3 v10.0, register an AdminPanelModule instead.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
$hookObject = GeneralUtility::makeInstance($className);
|
||||
if (!$hookObject instanceof AdminPanelViewHookInterface) {
|
||||
throw new \UnexpectedValueException(
|
||||
$className . ' must implement interface ' . AdminPanelViewHookInterface::class,
|
||||
1311942539
|
||||
);
|
||||
}
|
||||
$content = $hookObject->extendAdminPanel($moduleContent, $this);
|
||||
if ($content) {
|
||||
$moduleContent .= '<div class="typo3-adminPanel-section typo3-adminPanel-section-open">';
|
||||
$moduleContent .= ' <div class="typo3-adminPanel-section-body">';
|
||||
$moduleContent .= ' ' . $content;
|
||||
$moduleContent .= ' </div>';
|
||||
$moduleContent .= '</div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $moduleContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a single module with header panel
|
||||
*
|
||||
* @deprecated since TYPO3 v9 - only used in deprecated hook call (which triggers the corresponding deprecation error)
|
||||
* @param ModuleInterface $module
|
||||
* @return string
|
||||
*/
|
||||
protected function getModule(ModuleInterface $module): string
|
||||
{
|
||||
$output = [];
|
||||
|
||||
if ($module instanceof ConfigurableInterface && $module->isEnabled()) {
|
||||
$output[] = '<div class="typo3-adminPanel-section typo3-adminPanel-section-open">';
|
||||
$output[] = ' <div class="typo3-adminPanel-section-title">';
|
||||
$output[] = ' ' . $this->getSectionOpenerLink($module);
|
||||
$output[] = ' </div>';
|
||||
$output[] = '<div class="typo3-adminPanel-section-body">';
|
||||
$output[] = ' ' . $module->getContent();
|
||||
$output[] = '</div>';
|
||||
$output[] = '</div>';
|
||||
}
|
||||
|
||||
if ($module instanceof DataProviderInterface) {
|
||||
foreach ($module->getJavaScriptFiles() as $javaScriptFile) {
|
||||
$output[] =
|
||||
'<script src="' .
|
||||
PathUtility::getAbsoluteWebPath(GeneralUtility::getFileAbsFileName($javaScriptFile)) .
|
||||
'"></script>';
|
||||
}
|
||||
}
|
||||
|
||||
return implode('', $output);
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
* Admin Panel Layout Helper functions
|
||||
****************************************************/
|
||||
|
||||
/**
|
||||
* Wraps a string in a link which will open/close a certain part of the Admin Panel
|
||||
*
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0. Only used in deprecated hook call (which triggers the corresponding deprecation error)
|
||||
* @param ModuleInterface $module
|
||||
* @return string
|
||||
*/
|
||||
protected function getSectionOpenerLink(ModuleInterface $module): string
|
||||
{
|
||||
$identifier = $module->getIdentifier();
|
||||
$onclick = 'document.TSFE_ADMIN_PANEL_FORM[' .
|
||||
GeneralUtility::quoteJSvalue('TSFE_ADMIN_PANEL[display_' . $identifier . ']') .
|
||||
'].value=' .
|
||||
($this->getBackendUser()->uc['AdminPanel']['display_' . $identifier] ? '0' : '1') .
|
||||
';document.TSFE_ADMIN_PANEL_FORM.submit();return false;';
|
||||
|
||||
$output = [];
|
||||
$output[] = '<span class="typo3-adminPanel-section-title-identifier"></span>';
|
||||
$output[] = '<a href="javascript:void(0)" onclick="' . htmlspecialchars($onclick) . '">';
|
||||
$output[] = ' ' . htmlspecialchars($module->getLabel());
|
||||
$output[] = '</a>';
|
||||
$output[] = '<input type="hidden" name="TSFE_ADMIN_PANEL[display_' .
|
||||
$identifier .
|
||||
']" value="' .
|
||||
1 .
|
||||
'" />';
|
||||
|
||||
return implode('', $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the tool bar links for the "edit" section of the Admin Panel.
|
||||
*
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0. Use EditToolbarService instead or create buttons via fluid
|
||||
* @return string A string containing images wrapped in <a>-tags linking them to proper functions.
|
||||
*/
|
||||
public function ext_makeToolBar(): string
|
||||
{
|
||||
trigger_error(
|
||||
'AdminPanelView::ext_makeToolBar() will be removed in TYPO3 v10.0, use fluid and backend uri builder to create a toolbar.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
$editToolbarService = GeneralUtility::makeInstance(EditToolbarService::class);
|
||||
return $editToolbarService->createToolbar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate given key
|
||||
*
|
||||
* @param string $key Key for a label in the $LOCAL_LANG array of "EXT:core/Resources/Private/Language/locallang_tsfe.xlf
|
||||
* @param bool $convertWithHtmlspecialchars If TRUE the language-label will be sent through htmlspecialchars
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 - only used in deprecated methods
|
||||
* @return string The value for the $key
|
||||
*/
|
||||
protected function extGetLL($key, $convertWithHtmlspecialchars = true)
|
||||
{
|
||||
$labelStr = $this->getLanguageService()->getLL($key);
|
||||
if ($convertWithHtmlspecialchars) {
|
||||
$labelStr = htmlspecialchars($labelStr);
|
||||
}
|
||||
return $labelStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an additional stylesheet
|
||||
*
|
||||
* @return string
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 - implement AdminPanelModules via the new API (see AdminPanelModuleInterface)
|
||||
*/
|
||||
public function getAdminPanelHeaderData()
|
||||
{
|
||||
trigger_error(
|
||||
'AdminPanelView->getAdminPanelHeaderData() will be removed in TYPO3 v10.0. Implement AdminPanelModules via the new API (see AdminPanelModuleInterface).',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
$result = '';
|
||||
if (!empty($GLOBALS['TBE_STYLES']['stylesheets']['admPanel'])) {
|
||||
$stylesheet = GeneralUtility::locationHeaderUrl($GLOBALS['TBE_STYLES']['stylesheets']['admPanel']);
|
||||
$result = '<link rel="stylesheet" type="text/css" href="' .
|
||||
htmlspecialchars($stylesheet, ENT_QUOTES | ENT_HTML5) . '" />';
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an Admin Panel section ("module") is available for the user. If so, TRUE is returned.
|
||||
*
|
||||
* @param string $key The module key, eg. "edit", "preview", "info" etc.
|
||||
* @return bool
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 - implement AdminPanelModules via the new API (see AdminPanelModuleInterface)
|
||||
*/
|
||||
public function isAdminModuleEnabled($key)
|
||||
{
|
||||
trigger_error(
|
||||
'AdminPanelView->isAdminModuleEnabled() will be removed in TYPO3 v10.0. Implement AdminPanelModules via the new API (see AdminPanelModuleInterface).',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
$result = false;
|
||||
// Returns TRUE if the module checked is "preview" and the forcePreview flag is set.
|
||||
if ($key === 'preview' && $this->ext_forcePreview) {
|
||||
$result = true;
|
||||
} elseif (!empty($this->configuration['enable.']['all'])) {
|
||||
$result = true;
|
||||
} elseif (!empty($this->configuration['enable.'][$key])) {
|
||||
$result = true;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves any change in settings made in the Admin Panel.
|
||||
*
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 - implement AdminPanelModules via the new API (see AdminPanelModuleInterface)
|
||||
*/
|
||||
public function saveConfigOptions()
|
||||
{
|
||||
trigger_error(
|
||||
'AdminPanelView->saveConfigOptions() will be removed in TYPO3 v10.0. Implement AdminPanelModules via the new API (see AdminPanelModuleInterface).',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
$input = GeneralUtility::_GP('TSFE_ADMIN_PANEL');
|
||||
$beUser = $this->getBackendUser();
|
||||
if (is_array($input)) {
|
||||
// Setting
|
||||
$beUser->uc['AdminPanel'] = array_merge(
|
||||
!is_array($beUser->uc['AdminPanel']) ? [] : $beUser->uc['AdminPanel'],
|
||||
$input
|
||||
);
|
||||
unset($beUser->uc['AdminPanel']['action']);
|
||||
|
||||
foreach ($this->modules as $module) {
|
||||
if ($module->isEnabled()) {
|
||||
// We use TYPO3_REQUEST for compatibility reasons. The object and this method are deprecated anyway, this should be fine.
|
||||
$module->onSubmit($input, $GLOBALS['TYPO3_REQUEST']);
|
||||
}
|
||||
}
|
||||
// Saving
|
||||
$beUser->writeUC();
|
||||
// Flush fluid template cache
|
||||
$cacheManager = new CacheManager();
|
||||
$cacheManager->setCacheConfigurations($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']);
|
||||
$cacheManager->getCache('fluid_template')->flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for an Admin Panel setting.
|
||||
*
|
||||
* @param string $sectionName Module key
|
||||
* @param string $val Setting key
|
||||
* @return mixed The setting value
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 - implement AdminPanelModules via the new API (see AdminPanelModuleInterface)
|
||||
*/
|
||||
public function extGetFeAdminValue($sectionName, $val = '')
|
||||
{
|
||||
trigger_error(
|
||||
'AdminPanelView->extGetFeAdminValue() will be removed in TYPO3 v10.0. Implement AdminPanelModules via the new API (see AdminPanelModuleInterface).',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
if (!$this->isAdminModuleEnabled($sectionName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$beUser = $this->getBackendUser();
|
||||
// Exceptions where the values can be overridden (forced) from backend:
|
||||
// deprecated
|
||||
if (
|
||||
$sectionName === 'edit' && (
|
||||
$val === 'displayIcons' && $this->configuration['module.']['edit.']['forceDisplayIcons'] ||
|
||||
$val === 'displayFieldIcons' && $this->configuration['module.']['edit.']['forceDisplayFieldIcons'] ||
|
||||
$val === 'editNoPopup' && $this->configuration['module.']['edit.']['forceNoPopup']
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Override all settings with user TSconfig
|
||||
if ($val && isset($this->configuration['override.'][$sectionName . '.'][$val])) {
|
||||
return $this->configuration['override.'][$sectionName . '.'][$val];
|
||||
}
|
||||
if (!$val && isset($this->configuration['override.'][$sectionName])) {
|
||||
return $this->configuration['override.'][$sectionName];
|
||||
}
|
||||
|
||||
$returnValue = $val ? $beUser->uc['AdminPanel'][$sectionName . '_' . $val] : 1;
|
||||
|
||||
// Exception for preview
|
||||
if ($sectionName === 'preview' && $this->ext_forcePreview) {
|
||||
return !$val ? true : $returnValue;
|
||||
}
|
||||
|
||||
// See if the menu is expanded!
|
||||
return $this->isAdminModuleOpen($sectionName) ? $returnValue : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the force preview option.
|
||||
*
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 - see AdminPanelModule: Preview
|
||||
*/
|
||||
public function forcePreview()
|
||||
{
|
||||
trigger_error(
|
||||
'AdminPanelView->forcePreview() will be removed in TYPO3 v10.0. Use new AdminPanel Preview Module instead.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
$this->ext_forcePreview = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if admin panel module is open
|
||||
*
|
||||
* @param string $key Module key
|
||||
* @return bool TRUE, if the admin panel is open for the specified admin panel module key.
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 - use new AdminPanel API instead
|
||||
*/
|
||||
public function isAdminModuleOpen($key)
|
||||
{
|
||||
trigger_error(
|
||||
'AdminPanelView->isAdminModuleOpen() will be removed in TYPO3 v10.0. Use new AdminPanel API instead.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
return $this->getBackendUser()->uc['AdminPanel']['display_top'] &&
|
||||
$this->getBackendUser()->uc['AdminPanel']['display_' . $key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a row (with 4 columns) for content in a section of the Admin Panel.
|
||||
* It will take $pre as a key to a label to display and $element as the content to put into the forth cell.
|
||||
*
|
||||
* @param string $title Key to label
|
||||
* @param string $content The HTML content for the forth table cell.
|
||||
* @param string $checkbox The HTML for a checkbox or hidden fields.
|
||||
* @param string $innerDivClass The Class attribute for the td element.
|
||||
* @param string $outerDivClass The Class attribute for the tr element.
|
||||
* @return string HTML table row.
|
||||
* @see extGetHead()
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 - use new AdminPanel API instead
|
||||
*/
|
||||
public function extGetItem($title, $content = '', $checkbox = '', $outerDivClass = null, $innerDivClass = null)
|
||||
{
|
||||
trigger_error(
|
||||
'AdminPanelView->extGetItem() will be removed in TYPO3 v10.0. Use new AdminPanel API instead.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
$title = $title ? '<label for="' . htmlspecialchars($title) . '">' . $this->extGetLL($title) . '</label>' : '';
|
||||
$out = '';
|
||||
$out .= (string)$outerDivClass ? '<div class="' . htmlspecialchars($outerDivClass) . '">' : '<div>';
|
||||
$out .= (string)$innerDivClass ? '<div class="' . htmlspecialchars($innerDivClass) . '">' : '<div>';
|
||||
$out .= $checkbox . $title . $content . '</div></div>';
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a row (with colspan=4) which is a header for a section in the Admin Panel.
|
||||
* It will have a plus/minus icon and a label which is linked so that it submits the form which surrounds the whole Admin Panel when clicked, alterting the TSFE_ADMIN_PANEL[display_' . $pre . '] value
|
||||
* See the functions get*Module
|
||||
*
|
||||
* @param string $sectionSuffix The suffix to the display_ label. Also selects the label from the LOCAL_LANG array.
|
||||
* @return string HTML table row.
|
||||
* @see extGetItem()
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 - use new AdminPanel API instead
|
||||
*/
|
||||
public function extGetHead($sectionSuffix)
|
||||
{
|
||||
trigger_error(
|
||||
'AdminPanelView->extGetHead() will be removed in TYPO3 v10.0. Use new AdminPanel API instead.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
return $this->linkSectionHeader($sectionSuffix, $this->extGetLL($sectionSuffix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a string in a link which will open/close a certain part of the Admin Panel
|
||||
*
|
||||
* @param string $sectionSuffix The code for the display_ label/key
|
||||
* @param string $sectionTitle Title (HTML-escaped)
|
||||
* @param string $className The classname for the <a> tag
|
||||
* @return string $className Linked input string
|
||||
* @see extGetHead()
|
||||
* @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0 - use new AdminPanel API instead
|
||||
*/
|
||||
public function linkSectionHeader($sectionSuffix, $sectionTitle, $className = '')
|
||||
{
|
||||
trigger_error(
|
||||
'AdminPanelView->linkSectionHeader() will be removed in TYPO3 v10.0. Use new AdminPanel API instead.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
$onclick = 'document.TSFE_ADMIN_PANEL_FORM[' .
|
||||
GeneralUtility::quoteJSvalue('TSFE_ADMIN_PANEL[display_' . $sectionSuffix . ']') .
|
||||
'].value=' .
|
||||
($this->getBackendUser()->uc['AdminPanel']['display_' . $sectionSuffix] ? '0' : '1') .
|
||||
';document.TSFE_ADMIN_PANEL_FORM.submit();return false;';
|
||||
|
||||
$output = [];
|
||||
$output[] = '<span class="typo3-adminPanel-section-title-identifier"></span>';
|
||||
$output[] = '<a href="javascript:void(0)" onclick="' . htmlspecialchars($onclick) . '">';
|
||||
$output[] = ' ' . $sectionTitle;
|
||||
$output[] = '</a>';
|
||||
$output[] = '<input type="hidden" name="TSFE_ADMIN_PANEL[display_' .
|
||||
$sectionSuffix .
|
||||
']" value="' .
|
||||
(int)$this->isAdminModuleOpen($sectionSuffix) .
|
||||
'" />';
|
||||
|
||||
return implode('', $output);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Adminpanel\View;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interface for classes which hook into AdminPanelView
|
||||
*
|
||||
* @deprecated since TYPO3 v9 will be removed in TYPO3 v10.0 - see AdminPanelModuleInterface
|
||||
*/
|
||||
interface AdminPanelViewHookInterface
|
||||
{
|
||||
/**
|
||||
* Extend the adminPanel
|
||||
*
|
||||
* @param string $moduleContent Content of the admin panel
|
||||
* @param \TYPO3\CMS\Adminpanel\View\AdminPanelView $obj The adminPanel object
|
||||
* @return string Returns content of admin panel
|
||||
*/
|
||||
public function extendAdminPanel($moduleContent, AdminPanelView $obj);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ViewHelpers;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
|
||||
/**
|
||||
* Checks whether the given value is an array
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class IsArrayViewHelper extends AbstractViewHelper
|
||||
{
|
||||
public function initializeArguments()
|
||||
{
|
||||
$this->registerArgument('value', 'mixed', 'The variable being checked', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return bool
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
): bool {
|
||||
return is_array($arguments['value']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ViewHelpers;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Log\LogLevel;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Get speaking log level from constant
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class SpeakingLogLevelViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* First level cache of user names
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $usernameRuntimeCache = [];
|
||||
|
||||
/**
|
||||
* Initializes the arguments
|
||||
*/
|
||||
public function initializeArguments(): void
|
||||
{
|
||||
$this->registerArgument('level', 'int', 'Log Level', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve user name from backend user id.
|
||||
*
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return string Username or an empty string if there is no user with that UID
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
): string {
|
||||
return LogLevel::getName($arguments['level']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Adminpanel\ViewHelpers;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ContentProviderInterface;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleData;
|
||||
use TYPO3\CMS\Adminpanel\ModuleApi\ModuleDataStorageCollection;
|
||||
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* Render submodule content
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class SubModuleRenderViewHelper extends AbstractViewHelper
|
||||
{
|
||||
use CompileWithRenderStatic;
|
||||
|
||||
/**
|
||||
* First level cache of user names
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $usernameRuntimeCache = [];
|
||||
|
||||
/**
|
||||
* Initializes the arguments
|
||||
*/
|
||||
public function initializeArguments(): void
|
||||
{
|
||||
$this->registerArgument(
|
||||
'module',
|
||||
ContentProviderInterface::class,
|
||||
'SubModule instance to be rendered',
|
||||
true
|
||||
);
|
||||
$this->registerArgument('data', ModuleDataStorageCollection::class, 'Data to be used for rendering', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve user name from backend user id.
|
||||
*
|
||||
* @param array $arguments
|
||||
* @param \Closure $renderChildrenClosure
|
||||
* @param RenderingContextInterface $renderingContext
|
||||
* @return string Username or an empty string if there is no user with that UID
|
||||
*/
|
||||
public static function renderStatic(
|
||||
array $arguments,
|
||||
\Closure $renderChildrenClosure,
|
||||
RenderingContextInterface $renderingContext
|
||||
): string {
|
||||
$module = $arguments['module'];
|
||||
/** @var \TYPO3\CMS\Adminpanel\ModuleApi\ModuleDataStorageCollection $data */
|
||||
$data = $arguments['data'];
|
||||
$moduleData = $data->contains($module) ? $data->offsetGet($module) : new ModuleData();
|
||||
return $module->getContent($moduleData);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user