Commit dd5f4f90 authored by Benni Mack's avatar Benni Mack Committed by Georg Ringer
Browse files

[TASK] Extract workspace preview uri generation

All logic regarding generating preview links for workspaces has been
extracted into the "PreviewUriBuilder" method. Previously this was all
scattered between the WorkspaceService and the legacy "PreviewHook"
which was not used as a hook.

Separating this functionality allows to further split up the entry points
(Controllers / Handlers) and clean up concerns.

Resolves: #84940
Releases: master
Change-Id: I648fa12bab29ecb53ae319938d1086f95abfff58
Reviewed-on: https://review.typo3.org/56875


Tested-by: default avatarTYPO3com <no-reply@typo3.com>
Reviewed-by: default avatarMathias Schreiber <mathias.schreiber@typo3.com>
Tested-by: default avatarMathias Schreiber <mathias.schreiber@typo3.com>
Reviewed-by: Georg Ringer's avatarGeorg Ringer <georg.ringer@gmail.com>
Tested-by: Georg Ringer's avatarGeorg Ringer <georg.ringer@gmail.com>
parent fe115c75
......@@ -25,6 +25,7 @@ use TYPO3\CMS\Core\Utility\MathUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;
use TYPO3\CMS\Workspaces\Domain\Record\StageRecord;
use TYPO3\CMS\Workspaces\Domain\Record\WorkspaceRecord;
use TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder;
use TYPO3\CMS\Workspaces\Service\StagesService;
use TYPO3\CMS\Workspaces\Service\WorkspaceService;
......@@ -60,7 +61,7 @@ class ActionHandler
*/
public function generateWorkspacePreviewLink($uid)
{
return $this->workspaceService->generateWorkspacePreviewLink($uid);
return GeneralUtility::makeInstance(PreviewUriBuilder::class)->buildUriForPage((int)$uid);
}
/**
......@@ -71,7 +72,7 @@ class ActionHandler
*/
public function generateWorkspacePreviewLinksForAllLanguages($uid)
{
return $this->workspaceService->generateWorkspacePreviewLinksForAllLanguages($uid);
return GeneralUtility::makeInstance(PreviewUriBuilder::class)->buildUrisForAllLanguagesOfPage((int)$uid);
}
/**
......@@ -126,7 +127,7 @@ class ActionHandler
*/
public function viewSingleRecord($table, $uid)
{
return WorkspaceService::viewSingleRecord($table, $uid);
return GeneralUtility::makeInstance(PreviewUriBuilder::class)->buildUriForElement($table, $uid);
}
/**
......@@ -422,8 +423,7 @@ class ActionHandler
public function discardStagesFromPage($pageId)
{
$cmdMapArray = [];
$workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
$workspaceItemsArray = $workspaceService->selectVersionsInWorkspace(
$workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace(
$this->stageService->getWorkspaceId(),
$filter = 1,
$stage = -99,
......@@ -746,8 +746,7 @@ class ActionHandler
*/
public function sendPageToPreviousStage($id)
{
$workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
$workspaceItemsArray = $workspaceService->selectVersionsInWorkspace(
$workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace(
$this->stageService->getWorkspaceId(),
$filter = 1,
$stage = -99,
......@@ -757,7 +756,7 @@ class ActionHandler
);
list($currentStage, $previousStage) = $this->stageService->getPreviousStageForElementCollection($workspaceItemsArray);
// get only the relevant items for processing
$workspaceItemsArray = $workspaceService->selectVersionsInWorkspace(
$workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace(
$this->stageService->getWorkspaceId(),
$filter = 1,
$currentStage['uid'],
......@@ -781,8 +780,7 @@ class ActionHandler
*/
public function sendPageToNextStage($id)
{
$workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
$workspaceItemsArray = $workspaceService->selectVersionsInWorkspace(
$workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace(
$this->stageService->getWorkspaceId(),
$filter = 1,
$stage = -99,
......@@ -792,7 +790,7 @@ class ActionHandler
);
list($currentStage, $nextStage) = $this->stageService->getNextStageForElementCollection($workspaceItemsArray);
// get only the relevant items for processing
$workspaceItemsArray = $workspaceService->selectVersionsInWorkspace(
$workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace(
$this->stageService->getWorkspaceId(),
$filter = 1,
$currentStage['uid'],
......@@ -817,19 +815,17 @@ class ActionHandler
*/
public function updateStageChangeButtons($id)
{
$stageService = GeneralUtility::makeInstance(StagesService::class);
$workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
// fetch the next and previous stage
$workspaceItemsArray = $workspaceService->selectVersionsInWorkspace(
$stageService->getWorkspaceId(),
$workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace(
$this->stageService->getWorkspaceId(),
$filter = 1,
$stage = -99,
$id,
$recursionLevel = 0,
$selectionType = 'tables_modify'
);
list(, $nextStage) = $stageService->getNextStageForElementCollection($workspaceItemsArray);
list(, $previousStage) = $stageService->getPreviousStageForElementCollection($workspaceItemsArray);
list(, $nextStage) = $this->stageService->getNextStageForElementCollection($workspaceItemsArray);
list(, $previousStage) = $this->stageService->getPreviousStageForElementCollection($workspaceItemsArray);
$view = GeneralUtility::makeInstance(StandaloneView::class);
$extensionPath = ExtensionManagementUtility::extPath('workspaces');
......
......@@ -23,6 +23,7 @@ use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Versioning\VersionState;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
use TYPO3\CMS\Workspaces\Service\AdditionalColumnService;
......@@ -145,7 +146,6 @@ class ReviewController extends ActionController
$backendUser = $this->getBackendUser();
$moduleTemplate = $this->view->getModuleTemplate();
$wsService = GeneralUtility::makeInstance(WorkspaceService::class);
if (GeneralUtility::_GP('id')) {
$pageRecord = BackendUtility::getRecord('pages', GeneralUtility::_GP('id'));
if ($pageRecord) {
......@@ -153,7 +153,7 @@ class ReviewController extends ActionController
$this->view->assign('pageTitle', BackendUtility::getRecordTitle('pages', $pageRecord));
}
}
$wsList = $wsService->getAvailableWorkspaces();
$wsList = GeneralUtility::makeInstance(WorkspaceService::class)->getAvailableWorkspaces();
$activeWorkspace = $backendUser->workspace;
$performWorkspaceSwitch = false;
// Only admins see multiple tabs, we decided to use it this
......@@ -189,7 +189,7 @@ class ReviewController extends ActionController
'activeWorkspaceTitle' => WorkspaceService::getWorkspaceTitle($activeWorkspace),
]);
if ($wsService->canCreatePreviewLink(GeneralUtility::_GP('id'), $activeWorkspace)) {
if ($this->canCreatePreviewLink((int)GeneralUtility::_GP('id'), (int)$activeWorkspace)) {
$buttonBar = $moduleTemplate->getDocHeaderComponent()->getButtonBar();
$iconFactory = $moduleTemplate->getIconFactory();
$showButton = $buttonBar->makeLinkButton()
......@@ -344,6 +344,26 @@ class ReviewController extends ActionController
$this->pageRenderer->addInlineSetting('Workspaces', 'extension', $extension);
}
/**
* Determine whether this page for the current
*
* @param int $pageUid
* @param int $workspaceUid
* @return bool
*/
protected function canCreatePreviewLink(int $pageUid, int $workspaceUid): bool
{
if ($pageUid > 0 && $workspaceUid > 0) {
$pageRecord = BackendUtility::getRecord('pages', $pageUid);
BackendUtility::workspaceOL('pages', $pageRecord, $workspaceUid);
if (VersionState::cast($pageRecord['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) {
return false;
}
return true;
}
return false;
}
/**
* Gets the selected language.
*
......
......@@ -19,8 +19,8 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Messaging\FlashMessageService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder;
use TYPO3\CMS\Workspaces\Service\StagesService;
use TYPO3\CMS\Workspaces\Service\WorkspaceService;
/**
* Befunc service
......@@ -42,7 +42,7 @@ class BackendUtilityHook
public function preProcess(&$pageUid, $backPath, $rootLine, $anchorSection, &$viewScript, $additionalGetVars, $switchFocus)
{
if ($GLOBALS['BE_USER']->workspace !== 0) {
$viewScript = GeneralUtility::makeInstance(WorkspaceService::class)->generateWorkspaceSplittedPreviewLink($pageUid);
$viewScript = GeneralUtility::makeInstance(PreviewUriBuilder::class)->buildUriForWorkspaceSplitPreview((int)$pageUid, false);
}
}
......
......@@ -33,6 +33,7 @@ use TYPO3\CMS\Core\Utility\ArrayUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Versioning\VersionState;
use TYPO3\CMS\Workspaces\DataHandler\CommandMap;
use TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder;
use TYPO3\CMS\Workspaces\Service\StagesService;
use TYPO3\CMS\Workspaces\Service\WorkspaceService;
......@@ -565,6 +566,7 @@ class DataHandlerHook
}
// prepare and then send the emails
if (!empty($emails)) {
$previewUriBuilder = GeneralUtility::makeInstance(PreviewUriBuilder::class);
// Path to record is found:
list($elementTable, $elementUid) = explode(':', $elementName);
$elementUid = (int)$elementUid;
......@@ -606,10 +608,11 @@ class DataHandlerHook
$tempEmailMessage = $emailConfig['message'];
}
if (strpos($tempEmailMessage, '###PREVIEW_LINK###') !== false) {
$markers['###PREVIEW_LINK###'] = $this->workspaceService->generateWorkspacePreviewLink($elementUid);
$markers['###PREVIEW_LINK###'] = $previewUriBuilder->buildUriForPage((int)$elementUid);
}
unset($tempEmailMessage);
$markers['###SPLITTED_PREVIEW_LINK###'] = $this->workspaceService->generateWorkspaceSplittedPreviewLink($elementUid, true);
$markers['###SPLITTED_PREVIEW_LINK###'] = $previewUriBuilder->buildUriForWorkspaceSplitPreview((int)$elementUid, true);
// Hook for preprocessing of the content for formmails:
foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/version/class.tx_version_tcemain.php']['notifyStageChange-postModifyMarkers'] ?? [] as $className) {
$_procObj = GeneralUtility::makeInstance($className);
......
<?php
namespace TYPO3\CMS\Workspaces\Hook;
/*
* 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\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Hook for checking if the preview mode is activated
* preview mode = show a page of a workspace without having to log in
*/
class PreviewHook
{
/**
* Set preview keyword, eg:
* $previewUrl = GeneralUtility::getIndpEnv('TYPO3_SITE_URL').'index.php?ADMCMD_prev='.$this->compilePreviewKeyword($GLOBALS['BE_USER']->user['uid'], 120);
*
* @todo for sys_preview:
* - Add a comment which can be shown to previewer in frontend in some way (plus maybe ability to write back, take other action?)
* - Add possibility for the preview keyword to work in the backend as well: So it becomes a quick way to a certain action of sorts?
*
* @param string $backendUserUid 32 byte MD5 hash keyword for the URL: "?ADMCMD_prev=[keyword]
* @param int $ttl Time-To-Live for keyword
* @param int|null $fullWorkspace Which workspace ID to preview.
* @return string Returns keyword to use in URL for ADMCMD_prev=
*/
public function compilePreviewKeyword($backendUserUid, $ttl = 172800, $fullWorkspace = null)
{
$fieldData = [
'keyword' => md5(uniqid(microtime(), true)),
'tstamp' => $GLOBALS['EXEC_TIME'],
'endtime' => $GLOBALS['EXEC_TIME'] + $ttl,
'config' => json_encode([
'fullWorkspace' => $fullWorkspace,
'BEUSER_uid' => $backendUserUid
])
];
GeneralUtility::makeInstance(ConnectionPool::class)
->getConnectionForTable('sys_preview')
->insert(
'sys_preview',
$fieldData
);
return $fieldData['keyword'];
}
/**
* easy function to just return the number of hours
* a preview link is valid, based on the TSconfig value "options.workspaces.previewLinkTTLHours"
* by default, it's 48hs
*
* @return int The hours as a number
*/
public function getPreviewLinkLifetime()
{
$ttlHours = (int)$GLOBALS['BE_USER']->getTSConfigVal('options.workspaces.previewLinkTTLHours');
return $ttlHours ? $ttlHours : 24 * 2;
}
}
<?php
declare(strict_types = 1);
namespace TYPO3\CMS\Workspaces\Preview;
/*
* 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\Configuration\TranslationConfigurationProvider;
use TYPO3\CMS\Backend\Routing\UriBuilder;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Versioning\VersionState;
use TYPO3\CMS\Workspaces\Service\WorkspaceService;
/**
* Create links to pages when in a workspace for previewing purposes
*/
class PreviewUriBuilder
{
/**
* @var array
*/
protected $pageCache = [];
/**
* @var WorkspaceService
*/
protected $workspaceService;
public function __construct()
{
$this->workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
}
/**
* Generates a workspace preview link.
*
* @param int $uid The ID of the record to be linked
* @return string the full domain including the protocol http:// or https://, but without the trailing '/'
*/
public function buildUriForPage(int $uid): string
{
$previewKeyword = $this->compilePreviewKeyword(
$this->getBackendUser()->user['uid'],
$this->getPreviewLinkLifetime() * 3600,
$this->workspaceService->getCurrentWorkspace()
);
$linkParams = [
'ADMCMD_prev' => $previewKeyword,
'id' => $uid
];
return BackendUtility::getViewDomain($uid) . '/index.php?' . GeneralUtility::implodeArrayForUrl('', $linkParams);
}
/**
* Generate workspace preview links for all available languages of a page
*
* @param int $pageId
* @return array
*/
public function buildUrisForAllLanguagesOfPage(int $pageId): array
{
$previewUrl = $this->buildUriForPage($pageId);
$previewLanguages = $this->getAvailableLanguages($pageId);
$previewLinks = [];
foreach ($previewLanguages as $languageUid => $language) {
$previewLinks[$language] = $previewUrl . '&L=' . $languageUid;
}
return $previewLinks;
}
/**
* Generates a workspace split-bar preview link.
*
* @param int $uid The ID of the record to be linked
* @param bool $addDomain Parameter to decide if domain should be added to the generated link, FALSE per default
* @return string the preview link without the trailing '/'
*/
public function buildUriForWorkspaceSplitPreview(int $uid, bool $addDomain = false): string
{
// In case a $pageUid is submitted we need to make sure it points to a live-page
if ($uid > 0) {
$uid = $this->getLivePageUid($uid);
}
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
// the actual uid will be appended directly in BackendUtility Hook
$viewScript = $uriBuilder->buildUriFromRoute('workspace_previewcontrols', ['id' => '']);
if ($addDomain === true) {
$viewScript = $uriBuilder->buildUriFromRoute('workspace_previewcontrols', ['id' => $uid]);
return BackendUtility::getViewDomain($uid) . 'index.php?redirect_url=' . urlencode($viewScript);
}
return (string)$viewScript;
}
/**
* Generates a view Uri for a element.
*
* @param string $table Table to be used
* @param int $uid Uid of the version(!) record
* @param array $liveRecord Optional live record data
* @param array $versionRecord Optional version record data
* @return string
*/
public function buildUriForElement(string $table, int $uid, array $liveRecord = null, array $versionRecord = null): string
{
if ($table === 'pages') {
return BackendUtility::viewOnClick(BackendUtility::getLiveVersionIdOfRecord('pages', $uid));
}
if ($liveRecord === null) {
$liveRecord = BackendUtility::getLiveVersionOfRecord($table, $uid);
}
if ($versionRecord === null) {
$versionRecord = BackendUtility::getRecord($table, $uid);
}
if (VersionState::cast($versionRecord['t3ver_state'])->equals(VersionState::MOVE_POINTER)) {
$movePlaceholder = BackendUtility::getMovePlaceholder($table, $liveRecord['uid'], 'pid');
}
// Directly use pid value and consider move placeholders
$previewPageId = (empty($movePlaceholder['pid']) ? $liveRecord['pid'] : $movePlaceholder['pid']);
$additionalParameters = '&previewWS=' . $versionRecord['t3ver_wsid'];
// Add language parameter if record is a localization
if (BackendUtility::isTableLocalizable($table)) {
$languageField = $GLOBALS['TCA'][$table]['ctrl']['languageField'];
if ($versionRecord[$languageField] > 0) {
$additionalParameters .= '&L=' . $versionRecord[$languageField];
}
}
$pageTsConfig = BackendUtility::getPagesTSconfig($previewPageId);
$viewUrl = '';
// Directly use determined direct page id
if ($table === 'tt_content') {
$viewUrl = BackendUtility::viewOnClick($previewPageId, '', null, '', '', $additionalParameters);
} elseif (!empty($pageTsConfig['options.']['workspaces.']['previewPageId.'][$table]) || !empty($pageTsConfig['options.']['workspaces.']['previewPageId'])) {
// Analyze Page TSconfig options.workspaces.previewPageId
if (!empty($pageTsConfig['options.']['workspaces.']['previewPageId.'][$table])) {
$previewConfiguration = $pageTsConfig['options.']['workspaces.']['previewPageId.'][$table];
} else {
$previewConfiguration = $pageTsConfig['options.']['workspaces.']['previewPageId'];
}
// Extract possible settings (e.g. "field:pid")
list($previewKey, $previewValue) = explode(':', $previewConfiguration, 2);
if ($previewKey === 'field') {
$previewPageId = (int)$liveRecord[$previewValue];
} else {
$previewPageId = (int)$previewConfiguration;
}
$viewUrl = BackendUtility::viewOnClick($previewPageId, '', null, '', '', $additionalParameters);
} elseif (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['workspaces']['viewSingleRecord'])) {
// Call user function to render the single record view
$_params = [
'table' => $table,
'uid' => $uid,
'record' => $liveRecord,
'liveRecord' => $liveRecord,
'versionRecord' => $versionRecord,
];
$_funcRef = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['workspaces']['viewSingleRecord'];
$null = null;
$viewUrl = GeneralUtility::callUserFunction($_funcRef, $_params, $null);
}
return $viewUrl;
}
/**
* Adds an entry to the sys_preview database table and return the preview keyword.
*
* @param int $backendUserUid the user ID who created the preview link
* @param int $ttl Time-To-Live for keyword
* @param int|null $workspaceId Which workspace ID to preview.
* @return string Returns keyword to use in URL for ADMCMD_prev=, a 32 byte MD5 hash keyword for the URL: "?ADMCMD_prev=[keyword]
*/
protected function compilePreviewKeyword(int $backendUserUid, int $ttl = 172800, int $workspaceId = null): string
{
$keyword = md5(uniqid(microtime(), true));
GeneralUtility::makeInstance(ConnectionPool::class)
->getConnectionForTable('sys_preview')
->insert(
'sys_preview',
[
'keyword' => $keyword,
'tstamp' => $GLOBALS['EXEC_TIME'],
'endtime' => $GLOBALS['EXEC_TIME'] + $ttl,
'config' => json_encode([
'fullWorkspace' => $workspaceId,
'BEUSER_uid' => $backendUserUid
])
]
);
return $keyword;
}
/**
* easy function to just return the number of hours
* a preview link is valid, based on the TSconfig value "options.workspaces.previewLinkTTLHours"
* by default, it's 48hs
*
* @return int The hours as a number
*/
protected function getPreviewLinkLifetime(): int
{
$ttlHours = (int)$this->getBackendUser()->getTSConfigVal('options.workspaces.previewLinkTTLHours');
return $ttlHours ?: 24 * 2;
}
/**
* Find the Live-Uid for a given page,
* the results are cached at run-time to avoid too many database-queries
*
* @throws \InvalidArgumentException
* @param int $uid
* @return int
*/
protected function getLivePageUid(int $uid): int
{
if (!isset($this->pageCache[$uid])) {
$pageRecord = BackendUtility::getRecord('pages', $uid);
if (is_array($pageRecord)) {
$this->pageCache[$uid] = $pageRecord['t3ver_oid'] ? $pageRecord['t3ver_oid'] : $uid;
} else {
throw new \InvalidArgumentException('uid is supposed to point to an existing page - given value was: ' . $uid, 1290628113);
}
}
return $this->pageCache[$uid];
}
/**
* Get the available languages of a certain page, including language=0 if the user has access to it.
*
* @param int $pageId
* @return array assoc array with the languageId as key and the languageTitle as value
*/
protected function getAvailableLanguages(int $pageId): array
{
$languageOptions = [];
$translationConfigurationProvider = GeneralUtility::makeInstance(TranslationConfigurationProvider::class);
$systemLanguages = $translationConfigurationProvider->getSystemLanguages($pageId);
if ($this->getBackendUser()->checkLanguageAccess(0)) {
// Use configured label for default language
$languageOptions[0] = $systemLanguages[0]['title'];
}
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('pages');
$queryBuilder->getRestrictions()
->removeAll()
->add(GeneralUtility::makeInstance(DeletedRestriction::class))
->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
$result = $queryBuilder->select('sys_language_uid')
->from('pages')
->where(
$queryBuilder->expr()->eq(
$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
$queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
)
)
->execute();
while ($row = $result->fetch()) {
$languageId = (int)$row['sys_language_uid'];
// Only add links to active languages the user has access to
if (isset($systemLanguages[$languageId]) && $this->getBackendUser()->checkLanguageAccess($languageId)) {
$languageOptions[$languageId] = $systemLanguages[$languageId]['title'];
}
}
return $languageOptions;
}
/**
* @return BackendUserAuthentication
*/
protected function getBackendUser(): BackendUserAuthentication
{
return $GLOBALS['BE_USER'];
}
}