first commit
This commit is contained in:
commit
1218dd1517
12716 files changed
+989233
No files matched your search
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
|
||||
|
||||
/*
|
||||
* 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\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Backend\Toolbar\ClearCacheActionsHookInterface;
|
||||
use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Page\PageRenderer;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
|
||||
/**
|
||||
* Render cache clearing toolbar item
|
||||
* Adds a dropdown if there are more than one item to clear (usually for admins to render the flush all caches)
|
||||
*
|
||||
* The dropdown items can be extended via a hook named "cacheActions".
|
||||
*/
|
||||
class ClearCacheToolbarItem implements ToolbarItemInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $cacheActions = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $optionValues = [];
|
||||
|
||||
/**
|
||||
* @throws \UnexpectedValueException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar/ClearCacheMenu');
|
||||
$isAdmin = $this->getBackendUser()->isAdmin();
|
||||
$userTsConfig = $this->getBackendUser()->getTSConfig();
|
||||
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
|
||||
|
||||
// Clear all page-related caches
|
||||
if ($isAdmin || $userTsConfig['options.']['clearCache.']['pages'] ?? false) {
|
||||
$this->cacheActions[] = [
|
||||
'id' => 'pages',
|
||||
'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:flushPageCachesTitle',
|
||||
'description' => 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:flushPageCachesDescription',
|
||||
'href' => (string)$uriBuilder->buildUriFromRoute('tce_db', ['cacheCmd' => 'pages']),
|
||||
'iconIdentifier' => 'actions-system-cache-clear-impact-low'
|
||||
];
|
||||
$this->optionValues[] = 'pages';
|
||||
}
|
||||
|
||||
// Clearing of all caches is only shown if explicitly enabled via TSConfig
|
||||
// or if BE-User is admin and the TSconfig explicitly disables the possibility for admins.
|
||||
// This is useful for big production systems where admins accidentally could slow down the system.
|
||||
if (($userTsConfig['options.']['clearCache.']['all'] ?? false)
|
||||
|| ($isAdmin && (bool)($userTsConfig['options.']['clearCache.']['all'] ?? true))
|
||||
) {
|
||||
$this->cacheActions[] = [
|
||||
'id' => 'all',
|
||||
'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:flushAllCachesTitle2',
|
||||
'description' => 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:flushAllCachesDescription2',
|
||||
'href' => (string)$uriBuilder->buildUriFromRoute('tce_db', ['cacheCmd' => 'all']),
|
||||
'iconIdentifier' => 'actions-system-cache-clear-impact-high'
|
||||
];
|
||||
$this->optionValues[] = 'all';
|
||||
}
|
||||
|
||||
// Hook for manipulating cacheActions
|
||||
foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['additionalBackendItems']['cacheActions'] ?? [] as $cacheAction) {
|
||||
$hookObject = GeneralUtility::makeInstance($cacheAction);
|
||||
if (!$hookObject instanceof ClearCacheActionsHookInterface) {
|
||||
throw new \UnexpectedValueException($cacheAction . ' must implement interface ' . ClearCacheActionsHookInterface::class, 1228262000);
|
||||
}
|
||||
$hookObject->manipulateCacheActions($this->cacheActions, $this->optionValues);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the user has access to this toolbar item
|
||||
*
|
||||
* @return bool TRUE if user has access, FALSE if not
|
||||
*/
|
||||
public function checkAccess()
|
||||
{
|
||||
$backendUser = $this->getBackendUser();
|
||||
if ($backendUser->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
foreach ($this->optionValues as $value) {
|
||||
if ($backendUser->getTSConfig()['options.']['clearCache.'][$value] ?? false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render clear cache icon, based on the option if there is more than one icon or just one.
|
||||
*
|
||||
* @return string Icon HTML
|
||||
*/
|
||||
public function getItem()
|
||||
{
|
||||
if ($this->hasDropDown()) {
|
||||
return $this->getFluidTemplateObject('ClearCacheToolbarItem.html')->render();
|
||||
}
|
||||
$view = $this->getFluidTemplateObject('ClearCacheToolbarItemSingle.html');
|
||||
$cacheAction = end($this->cacheActions);
|
||||
$view->assignMultiple([
|
||||
'link' => $cacheAction['href'],
|
||||
'title' => $cacheAction['title'],
|
||||
'iconIdentifier' => $cacheAction['iconIdentifier'],
|
||||
]);
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render drop down
|
||||
*
|
||||
* @return string Drop down HTML
|
||||
*/
|
||||
public function getDropDown()
|
||||
{
|
||||
$view = $this->getFluidTemplateObject('ClearCacheToolbarItemDropDown.html');
|
||||
$view->assign('cacheActions', $this->cacheActions);
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* No additional attributes needed.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAdditionalAttributes()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* This item has a drop down if there is more than one cache action available for the current Backend user.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasDropDown()
|
||||
{
|
||||
return count($this->cacheActions) > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Position relative to others
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getIndex()
|
||||
{
|
||||
return 25;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current BE user.
|
||||
*
|
||||
* @return BackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUser()
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PageRenderer
|
||||
*/
|
||||
protected function getPageRenderer()
|
||||
{
|
||||
return GeneralUtility::makeInstance(PageRenderer::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new standalone view, shorthand function
|
||||
*
|
||||
* @param string $filename Which templateFile should be used.
|
||||
* @return StandaloneView
|
||||
*/
|
||||
protected function getFluidTemplateObject(string $filename): StandaloneView
|
||||
{
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$view->setLayoutRootPaths(['EXT:backend/Resources/Private/Layouts']);
|
||||
$view->setPartialRootPaths(['EXT:backend/Resources/Private/Partials/ToolbarItems']);
|
||||
$view->setTemplateRootPaths(['EXT:backend/Resources/Private/Templates/ToolbarItems']);
|
||||
|
||||
$view->setTemplate($filename);
|
||||
|
||||
$view->getRequest()->setControllerExtensionName('Backend');
|
||||
return $view;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
|
||||
|
||||
/*
|
||||
* 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\Domain\Model\Module\BackendModule;
|
||||
use TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository;
|
||||
use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
|
||||
/**
|
||||
* Help toolbar item
|
||||
*/
|
||||
class HelpToolbarItem implements ToolbarItemInterface
|
||||
{
|
||||
/**
|
||||
* @var BackendModule
|
||||
*/
|
||||
protected $helpModuleMenu;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$backendModuleRepository = GeneralUtility::makeInstance(BackendModuleRepository::class);
|
||||
$helpModuleMenu = $backendModuleRepository->findByModuleName('help');
|
||||
if ($helpModuleMenu && $helpModuleMenu->getChildren()->count() > 0) {
|
||||
$this->helpModuleMenu = $helpModuleMenu;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Users see this if a module is available
|
||||
*
|
||||
* @return bool TRUE
|
||||
*/
|
||||
public function checkAccess()
|
||||
{
|
||||
return (bool)$this->helpModuleMenu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render help icon
|
||||
*
|
||||
* @return string toolbar item for the help icon
|
||||
*/
|
||||
public function getItem()
|
||||
{
|
||||
return $this->getFluidTemplateObject('HelpToolbarItem.html')->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render drop down
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDropDown()
|
||||
{
|
||||
$view = $this->getFluidTemplateObject('HelpToolbarItemDropDown.html');
|
||||
$view->assign('modules', $this->helpModuleMenu->getChildren());
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* No additional attributes needed.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAdditionalAttributes()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* This item has a drop down
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasDropDown()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Position relative to others
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getIndex()
|
||||
{
|
||||
return 70;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new standalone view, shorthand function
|
||||
*
|
||||
* @param string $filename Which templateFile should be used.
|
||||
* @return StandaloneView
|
||||
*/
|
||||
protected function getFluidTemplateObject(string $filename): StandaloneView
|
||||
{
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$view->setLayoutRootPaths(['EXT:backend/Resources/Private/Layouts']);
|
||||
$view->setPartialRootPaths(['EXT:backend/Resources/Private/Partials/ToolbarItems']);
|
||||
$view->setTemplateRootPaths(['EXT:backend/Resources/Private/Templates/ToolbarItems']);
|
||||
$view->setTemplate($filename);
|
||||
|
||||
$view->getRequest()->setControllerExtensionName('Backend');
|
||||
return $view;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
|
||||
|
||||
/*
|
||||
* 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\Domain\Repository\Module\BackendModuleRepository;
|
||||
use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
|
||||
use TYPO3\CMS\Core\Page\PageRenderer;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
|
||||
/**
|
||||
* Adds backend live search to the toolbar by adding JavaScript and adding an input search field
|
||||
*/
|
||||
class LiveSearchToolbarItem implements ToolbarItemInterface
|
||||
{
|
||||
/**
|
||||
* Loads the needed JavaScript file, ands includes it to the page renderer
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/LiveSearch');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the user has access to this toolbar item,
|
||||
* only allowed when the list module is available.
|
||||
* Live search is heavily dependent on the list module and only available when that module is.
|
||||
*
|
||||
* @return bool TRUE if user has access, FALSE if not
|
||||
*/
|
||||
public function checkAccess()
|
||||
{
|
||||
$backendModuleRepository = GeneralUtility::makeInstance(BackendModuleRepository::class);
|
||||
$listModule = $backendModuleRepository->findByModuleName('web_list');
|
||||
return $listModule !== null && $listModule !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render search field
|
||||
*
|
||||
* @return string Live search form HTML
|
||||
*/
|
||||
public function getItem()
|
||||
{
|
||||
return $this->getFluidTemplateObject('LiveSearchToolbarItem.html')->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* This item needs to additional attributes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAdditionalAttributes()
|
||||
{
|
||||
return ['class' => 'toolbar-item-search t3js-toolbar-item-search'];
|
||||
}
|
||||
|
||||
/**
|
||||
* This item has no drop down
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasDropDown()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* No drop down here
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDropDown()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Position relative to others, live search should be very right
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getIndex()
|
||||
{
|
||||
return 90;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current PageRenderer
|
||||
*
|
||||
* @return PageRenderer
|
||||
*/
|
||||
protected function getPageRenderer()
|
||||
{
|
||||
return GeneralUtility::makeInstance(PageRenderer::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new standalone view, shorthand function
|
||||
*
|
||||
* @param string $filename Which templateFile should be used.
|
||||
* @return StandaloneView
|
||||
*/
|
||||
protected function getFluidTemplateObject(string $filename): StandaloneView
|
||||
{
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$view->setLayoutRootPaths(['EXT:backend/Resources/Private/Layouts']);
|
||||
$view->setPartialRootPaths(['EXT:backend/Resources/Private/Partials/ToolbarItems']);
|
||||
$view->setTemplateRootPaths(['EXT:backend/Resources/Private/Templates/ToolbarItems']);
|
||||
|
||||
$view->setTemplate($filename);
|
||||
|
||||
$view->getRequest()->setControllerExtensionName('Backend');
|
||||
return $view;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
|
||||
|
||||
/*
|
||||
* 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\Backend\Shortcut\ShortcutRepository;
|
||||
use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
|
||||
use TYPO3\CMS\Core\Page\PageRenderer;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
|
||||
/**
|
||||
* Class to render the shortcut menu
|
||||
*
|
||||
* @internal This class is a specific Backend implementation and is not considered part of the Public TYPO3 API.
|
||||
*/
|
||||
class ShortcutToolbarItem implements ToolbarItemInterface
|
||||
{
|
||||
/**
|
||||
* @var ShortcutRepository
|
||||
*/
|
||||
protected $shortcutRepository;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->shortcutRepository = GeneralUtility::makeInstance(ShortcutRepository::class);
|
||||
|
||||
$pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
|
||||
$pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar/ShortcutMenu');
|
||||
$languageService = $this->getLanguageService();
|
||||
$languageFile = 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf';
|
||||
$pageRenderer->addInlineLanguageLabelArray([
|
||||
'bookmark.delete' => $languageService->sL($languageFile . ':toolbarItems.bookmarksDelete'),
|
||||
'bookmark.confirmDelete' => $languageService->sL($languageFile . ':toolbarItems.confirmBookmarksDelete'),
|
||||
'bookmark.create' => $languageService->sL($languageFile . ':toolbarItems.createBookmark'),
|
||||
'bookmark.savedTitle' => $languageService->sL($languageFile . ':toolbarItems.bookmarkSavedTitle'),
|
||||
'bookmark.savedMessage' => $languageService->sL($languageFile . ':toolbarItems.bookmarkSavedMessage'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the user has access to this toolbar item
|
||||
*
|
||||
* @return bool TRUE if user has access, FALSE if not
|
||||
*/
|
||||
public function checkAccess()
|
||||
{
|
||||
return (bool)($this->getBackendUser()->getTSConfig()['options.']['enableBookmarks'] ?? false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render shortcut icon
|
||||
*
|
||||
* @return string HTML
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidExtensionNameException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getItem()
|
||||
{
|
||||
return $this->getFluidTemplateObject('Item.html')->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* This item has a drop down
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasDropDown()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render drop down content
|
||||
*
|
||||
* @return string HTML
|
||||
*/
|
||||
public function getDropDown()
|
||||
{
|
||||
$shortcutMenu = [];
|
||||
$groups = $this->shortcutRepository->getGroupsFromShortcuts();
|
||||
arsort($groups, SORT_NUMERIC);
|
||||
|
||||
foreach ($groups as $groupId => $groupLabel) {
|
||||
$shortcutMenu[] = [
|
||||
'id' => (int)$groupId,
|
||||
'title' => $groupLabel,
|
||||
'shortcuts' => $this->shortcutRepository->getShortcutsByGroup($groupId),
|
||||
];
|
||||
}
|
||||
|
||||
$dropDownView = $this->getFluidTemplateObject('DropDown.html');
|
||||
$dropDownView->assign('shortcutMenu', $shortcutMenu);
|
||||
|
||||
return $dropDownView->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* This toolbar item needs no additional attributes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAdditionalAttributes()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Position relative to others, live search should be very right
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getIndex()
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a new standalone view, shorthand function
|
||||
*
|
||||
* @param string $templateFilename
|
||||
* @return StandaloneView
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidExtensionNameException
|
||||
* @throws \InvalidArgumentException
|
||||
* @internal param string $templateFile
|
||||
*/
|
||||
protected function getFluidTemplateObject(string $templateFilename): StandaloneView
|
||||
{
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$view->setLayoutRootPaths(['EXT:backend/Resources/Private/Layouts']);
|
||||
$view->setPartialRootPaths(['EXT:backend/Resources/Private/Partials']);
|
||||
$view->setTemplateRootPaths(['EXT:backend/Resources/Private/Templates/ShortcutToolbarItem']);
|
||||
$view->setTemplate($templateFilename);
|
||||
$view->getRequest()->setControllerExtensionName('Backend');
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current BE user.
|
||||
*
|
||||
* @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUser()
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \TYPO3\CMS\Core\Localization\LanguageService
|
||||
*/
|
||||
protected function getLanguageService()
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,440 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
|
||||
|
||||
/*
|
||||
* 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\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus;
|
||||
use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Page\PageRenderer;
|
||||
use TYPO3\CMS\Core\Routing\RouteNotFoundException;
|
||||
use TYPO3\CMS\Core\Utility\CommandUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\StringUtility;
|
||||
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManager;
|
||||
use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
|
||||
/**
|
||||
* Render system info toolbar item
|
||||
*/
|
||||
class SystemInformationToolbarItem implements ToolbarItemInterface
|
||||
{
|
||||
/**
|
||||
* Number displayed as badge on the dropdown trigger
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $totalCount = 0;
|
||||
|
||||
/**
|
||||
* Holds the highest severity
|
||||
*
|
||||
* @var InformationStatus
|
||||
*/
|
||||
protected $highestSeverity;
|
||||
|
||||
/**
|
||||
* The CSS class for the badge
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $severityBadgeClass = '';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $systemInformation = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $systemMessages = [];
|
||||
|
||||
/**
|
||||
* @var Dispatcher
|
||||
*/
|
||||
protected $signalSlotDispatcher;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $maximumCountInBadge = 99;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar/SystemInformationMenu');
|
||||
$this->highestSeverity = InformationStatus::cast(InformationStatus::STATUS_INFO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a system message.
|
||||
* This is a callback method for signal receivers.
|
||||
*
|
||||
* @param string $text The text to be displayed
|
||||
* @param string $status The status of this system message
|
||||
* @param int $count Will be added to the total count
|
||||
* @param string $module The associated module
|
||||
* @param string $params Query string with additional parameters
|
||||
*/
|
||||
public function addSystemMessage($text, $status = InformationStatus::STATUS_OK, $count = 0, $module = '', $params = '')
|
||||
{
|
||||
$this->totalCount += (int)$count;
|
||||
|
||||
/** @var InformationStatus $messageSeverity */
|
||||
$messageSeverity = InformationStatus::cast($status);
|
||||
// define the severity for the badge
|
||||
if ($messageSeverity->isGreaterThan($this->highestSeverity)) {
|
||||
$this->highestSeverity = $messageSeverity;
|
||||
}
|
||||
|
||||
$this->systemMessages[] = [
|
||||
'module' => $module,
|
||||
'params' => $params,
|
||||
'count' => (int)$count,
|
||||
'status' => $messageSeverity,
|
||||
'text' => $text
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a system information.
|
||||
* This is a callback method for signal receivers.
|
||||
*
|
||||
* @param string $title The title of this system information
|
||||
* @param string $value The associated value
|
||||
* @param string $iconIdentifier The icon identifier
|
||||
* @param string $status The status of this system information
|
||||
*/
|
||||
public function addSystemInformation($title, $value, $iconIdentifier, $status = InformationStatus::STATUS_NOTICE)
|
||||
{
|
||||
$this->systemInformation[] = [
|
||||
'title' => $title,
|
||||
'value' => $value,
|
||||
'iconIdentifier' => $iconIdentifier,
|
||||
'status' => $status
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the user has access to this toolbar item
|
||||
*
|
||||
* @return bool TRUE if user has access, FALSE if not
|
||||
*/
|
||||
public function checkAccess()
|
||||
{
|
||||
return $this->getBackendUserAuthentication()->isAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render system information dropdown
|
||||
*
|
||||
* @return string Icon HTML
|
||||
*/
|
||||
public function getItem()
|
||||
{
|
||||
return $this->getFluidTemplateObject('SystemInformationToolbarItem.html')->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render drop down
|
||||
*
|
||||
* @return string Drop down HTML
|
||||
*/
|
||||
public function getDropDown()
|
||||
{
|
||||
if (!$this->checkAccess()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$this->collectInformation();
|
||||
|
||||
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
|
||||
$view = $this->getFluidTemplateObject('SystemInformationDropDown.html');
|
||||
|
||||
try {
|
||||
$environmentToolUrl = (string)$uriBuilder->buildUriFromRoute('tools_toolsenvironment');
|
||||
} catch (RouteNotFoundException $e) {
|
||||
$environmentToolUrl = '';
|
||||
}
|
||||
|
||||
$view->assignMultiple([
|
||||
'environmentToolUrl' => $environmentToolUrl,
|
||||
'messages' => $this->systemMessages,
|
||||
'count' => $this->totalCount > $this->maximumCountInBadge ? $this->maximumCountInBadge . '+' : $this->totalCount,
|
||||
'severityBadgeClass' => $this->severityBadgeClass,
|
||||
'systemInformation' => $this->systemInformation
|
||||
]);
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* No additional attributes needed.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAdditionalAttributes()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* This item has a drop down
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasDropDown()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Position relative to others
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getIndex()
|
||||
{
|
||||
return 75;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the information for the menu
|
||||
*/
|
||||
protected function collectInformation()
|
||||
{
|
||||
$this->getTypo3Version();
|
||||
$this->getWebServer();
|
||||
$this->getPhpVersion();
|
||||
$this->getDatabase();
|
||||
$this->getApplicationContext();
|
||||
$this->getComposerMode();
|
||||
$this->getGitRevision();
|
||||
$this->getOperatingSystem();
|
||||
|
||||
$this->emitGetSystemInformation();
|
||||
$this->emitLoadMessages();
|
||||
|
||||
$this->severityBadgeClass = !$this->highestSeverity->equals(InformationStatus::STATUS_NOTICE) ? 'badge-' . (string)$this->highestSeverity : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the TYPO3 version
|
||||
*/
|
||||
protected function getTypo3Version()
|
||||
{
|
||||
$this->systemInformation[] = [
|
||||
'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.typo3-version',
|
||||
'value' => VersionNumberUtility::getCurrentTypo3Version(),
|
||||
'iconIdentifier' => 'information-typo3-version'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the webserver software
|
||||
*/
|
||||
protected function getWebServer()
|
||||
{
|
||||
$this->systemInformation[] = [
|
||||
'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.webserver',
|
||||
'value' => $_SERVER['SERVER_SOFTWARE'],
|
||||
'iconIdentifier' => 'information-webserver'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the PHP version
|
||||
*/
|
||||
protected function getPhpVersion()
|
||||
{
|
||||
$this->systemInformation[] = [
|
||||
'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.phpversion',
|
||||
'value' => PHP_VERSION,
|
||||
'iconIdentifier' => 'information-php-version'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the database info
|
||||
*/
|
||||
protected function getDatabase()
|
||||
{
|
||||
foreach (GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionNames() as $connectionName) {
|
||||
$this->systemInformation[] = [
|
||||
'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.database',
|
||||
'titleAddition' => $connectionName,
|
||||
'value' => GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getConnectionByName($connectionName)
|
||||
->getServerVersion(),
|
||||
'iconIdentifier' => 'information-database'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the application context
|
||||
*/
|
||||
protected function getApplicationContext()
|
||||
{
|
||||
$applicationContext = GeneralUtility::getApplicationContext();
|
||||
$this->systemInformation[] = [
|
||||
'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.applicationcontext',
|
||||
'value' => (string)$applicationContext,
|
||||
'status' => $applicationContext->isProduction() ? InformationStatus::STATUS_OK : InformationStatus::STATUS_WARNING,
|
||||
'iconIdentifier' => 'information-application-context'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the information if the Composer mode is enabled or disabled to the displayed system information
|
||||
*/
|
||||
protected function getComposerMode()
|
||||
{
|
||||
if (!Environment::isComposerMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->systemInformation[] = [
|
||||
'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.composerMode',
|
||||
'value' => $GLOBALS['LANG']->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.enabled'),
|
||||
'iconIdentifier' => 'information-composer-mode'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current GIT revision and branch
|
||||
*/
|
||||
protected function getGitRevision()
|
||||
{
|
||||
if (!StringUtility::endsWith(TYPO3_version, '-dev') || SystemEnvironmentBuilder::isFunctionDisabled('exec')) {
|
||||
return;
|
||||
}
|
||||
// check if git exists
|
||||
CommandUtility::exec('git --version', $_, $returnCode);
|
||||
if ((int)$returnCode !== 0) {
|
||||
// git is not available
|
||||
return;
|
||||
}
|
||||
|
||||
$revision = trim(CommandUtility::exec('git rev-parse --short HEAD'));
|
||||
$branch = trim(CommandUtility::exec('git rev-parse --abbrev-ref HEAD'));
|
||||
if (!empty($revision) && !empty($branch)) {
|
||||
$this->systemInformation[] = [
|
||||
'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.gitrevision',
|
||||
'value' => sprintf('%s [%s]', $revision, $branch),
|
||||
'iconIdentifier' => 'information-git'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the system kernel and version
|
||||
*/
|
||||
protected function getOperatingSystem()
|
||||
{
|
||||
switch (PHP_OS_FAMILY) {
|
||||
case 'Linux':
|
||||
$icon = 'linux';
|
||||
break;
|
||||
case 'Darwin':
|
||||
$icon = 'apple';
|
||||
break;
|
||||
case 'Windows':
|
||||
$icon = 'windows';
|
||||
break;
|
||||
default:
|
||||
$icon = 'unknown';
|
||||
}
|
||||
$this->systemInformation[] = [
|
||||
'title' => 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:toolbarItems.sysinfo.operatingsystem',
|
||||
'value' => PHP_OS . ' ' . php_uname('r'),
|
||||
'iconIdentifier' => 'information-os-' . $icon
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits the "getSystemInformation" signal
|
||||
*/
|
||||
protected function emitGetSystemInformation()
|
||||
{
|
||||
$this->getSignalSlotDispatcher()->dispatch(__CLASS__, 'getSystemInformation', [$this]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits the "loadMessages" signal
|
||||
*/
|
||||
protected function emitLoadMessages()
|
||||
{
|
||||
$this->getSignalSlotDispatcher()->dispatch(__CLASS__, 'loadMessages', [$this]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new standalone view, shorthand function
|
||||
*
|
||||
* @param string $filename Which templateFile should be used.
|
||||
* @return StandaloneView
|
||||
*/
|
||||
protected function getFluidTemplateObject(string $filename): StandaloneView
|
||||
{
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$view->setLayoutRootPaths(['EXT:backend/Resources/Private/Layouts']);
|
||||
$view->setPartialRootPaths(['EXT:backend/Resources/Private/Partials/ToolbarItems']);
|
||||
$view->setTemplateRootPaths(['EXT:backend/Resources/Private/Templates/ToolbarItems']);
|
||||
|
||||
$view->setTemplate($filename);
|
||||
|
||||
$view->getRequest()->setControllerExtensionName('Backend');
|
||||
return $view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current BE user.
|
||||
*
|
||||
* @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUserAuthentication()
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current PageRenderer
|
||||
*
|
||||
* @return PageRenderer
|
||||
*/
|
||||
protected function getPageRenderer()
|
||||
{
|
||||
return GeneralUtility::makeInstance(PageRenderer::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SignalSlot dispatcher
|
||||
*
|
||||
* @return Dispatcher
|
||||
*/
|
||||
protected function getSignalSlotDispatcher()
|
||||
{
|
||||
if (!isset($this->signalSlotDispatcher)) {
|
||||
$this->signalSlotDispatcher = GeneralUtility::makeInstance(ObjectManager::class)->get(Dispatcher::class);
|
||||
}
|
||||
return $this->signalSlotDispatcher;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
|
||||
|
||||
/*
|
||||
* 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\Domain\Repository\Module\BackendModuleRepository;
|
||||
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\View\StandaloneView;
|
||||
|
||||
/**
|
||||
* User toolbar item
|
||||
*
|
||||
* @internal This class is a specific Backend implementation and is not considered part of the Public TYPO3 API.
|
||||
*/
|
||||
class UserToolbarItem implements ToolbarItemInterface
|
||||
{
|
||||
/**
|
||||
* Item is always enabled
|
||||
*
|
||||
* @return bool TRUE
|
||||
*/
|
||||
public function checkAccess()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render username and an icon
|
||||
*
|
||||
* @return string HTML
|
||||
*/
|
||||
public function getItem()
|
||||
{
|
||||
$backendUser = $this->getBackendUser();
|
||||
$view = $this->getFluidTemplateObject('UserToolbarItem.html');
|
||||
$view->assignMultiple([
|
||||
'currentUser' => $backendUser->user,
|
||||
'switchUserMode' => $backendUser->user['ses_backuserid'],
|
||||
]);
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render drop down
|
||||
*
|
||||
* @return string HTML
|
||||
*/
|
||||
public function getDropDown()
|
||||
{
|
||||
$backendUser = $this->getBackendUser();
|
||||
|
||||
/** @var BackendModuleRepository $backendModuleRepository */
|
||||
$backendModuleRepository = GeneralUtility::makeInstance(BackendModuleRepository::class);
|
||||
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
|
||||
|
||||
$mostRecentUsers = [];
|
||||
if (ExtensionManagementUtility::isLoaded('beuser')
|
||||
&& $backendUser->isAdmin()
|
||||
&& (int)$backendUser->user['ses_backuserid'] === 0
|
||||
&& isset($backendUser->uc['recentSwitchedToUsers'])
|
||||
&& is_array($backendUser->uc['recentSwitchedToUsers'])
|
||||
) {
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('be_users');
|
||||
$result = $queryBuilder
|
||||
->select('uid', 'username', 'realName')
|
||||
->from('be_users')
|
||||
->where(
|
||||
$queryBuilder->expr()->in('uid', $queryBuilder->createNamedParameter($backendUser->uc['recentSwitchedToUsers'], Connection::PARAM_INT_ARRAY))
|
||||
)->execute();
|
||||
|
||||
// Flip the array to have a "sorted" list of items
|
||||
$mostRecentUsers = array_flip($backendUser->uc['recentSwitchedToUsers']);
|
||||
|
||||
while ($row = $result->fetch()) {
|
||||
$row['switchUserLink'] = (string)$uriBuilder->buildUriFromRoute(
|
||||
'system_BeuserTxBeuser',
|
||||
[
|
||||
'SwitchUser' => $row['uid']
|
||||
]
|
||||
);
|
||||
|
||||
$mostRecentUsers[$row['uid']] = $row;
|
||||
}
|
||||
|
||||
// Remove any item that is not an array (means, the stored uid is not available anymore)
|
||||
$mostRecentUsers = array_filter($mostRecentUsers, function ($record) {
|
||||
return is_array($record);
|
||||
});
|
||||
|
||||
$availableUsers = array_keys($mostRecentUsers);
|
||||
if (!empty(array_diff($backendUser->uc['recentSwitchedToUsers'], $availableUsers))) {
|
||||
$backendUser->uc['recentSwitchedToUsers'] = $availableUsers;
|
||||
$backendUser->writeUC();
|
||||
}
|
||||
}
|
||||
|
||||
$view = $this->getFluidTemplateObject('UserToolbarItemDropDown.html');
|
||||
$view->assignMultiple([
|
||||
'modules' => $backendModuleRepository->findByModuleName('user')->getChildren(),
|
||||
'logoutUrl' => (string)$uriBuilder->buildUriFromRoute('logout'),
|
||||
'switchUserMode' => $this->getBackendUser()->user['ses_backuserid'],
|
||||
'recentUsers' => $mostRecentUsers,
|
||||
]);
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an additional class if user is in "switch user" mode
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAdditionalAttributes()
|
||||
{
|
||||
$result = [
|
||||
'class' => 'toolbar-item-user'
|
||||
];
|
||||
if ($this->getBackendUser()->user['ses_backuserid']) {
|
||||
$result['class'] .= ' su-user';
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This item has a drop down
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasDropDown()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Position relative to others
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getIndex()
|
||||
{
|
||||
return 80;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current BE user.
|
||||
*
|
||||
* @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUser()
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new standalone view, shorthand function
|
||||
*
|
||||
* @param string $filename Which templateFile should be used.
|
||||
*
|
||||
* @return StandaloneView
|
||||
*/
|
||||
protected function getFluidTemplateObject(string $filename): StandaloneView
|
||||
{
|
||||
$view = GeneralUtility::makeInstance(StandaloneView::class);
|
||||
$view->setLayoutRootPaths(['EXT:backend/Resources/Private/Layouts']);
|
||||
$view->setPartialRootPaths(['EXT:backend/Resources/Private/Partials/ToolbarItems']);
|
||||
$view->setTemplateRootPaths(['EXT:backend/Resources/Private/Templates/ToolbarItems']);
|
||||
|
||||
$view->setTemplate($filename);
|
||||
|
||||
$view->getRequest()->setControllerExtensionName('Backend');
|
||||
return $view;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user