first commit
This commit is contained in:
commit
1218dd1517
12716 files changed
+989233
No files matched your search
@@ -0,0 +1,296 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Backend\Domain\Model\Module;
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Model for menu entries
|
||||
*/
|
||||
class BackendModule
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $title = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $icon = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $link = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $onClick = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $navigationComponentId = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $navigationFrameScript = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $navigationFrameScriptParameters = '';
|
||||
|
||||
/**
|
||||
* @var \SplObjectStorage
|
||||
*/
|
||||
protected $children;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $collapsed = false;
|
||||
|
||||
/**
|
||||
* construct
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->children = new \SplObjectStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set children
|
||||
*
|
||||
* @param \SplObjectStorage $children
|
||||
*/
|
||||
public function setChildren($children)
|
||||
{
|
||||
$this->children = $children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get children
|
||||
*
|
||||
* @return \SplObjectStorage
|
||||
*/
|
||||
public function getChildren()
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Child
|
||||
*
|
||||
* @param \TYPO3\CMS\Backend\Domain\Model\Module\BackendModule $child
|
||||
*/
|
||||
public function addChild(\TYPO3\CMS\Backend\Domain\Model\Module\BackendModule $child)
|
||||
{
|
||||
$this->children->attach($child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set icon
|
||||
*
|
||||
* @param string $icon
|
||||
*/
|
||||
public function setIcon($icon)
|
||||
{
|
||||
$this->icon = $icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get icon
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIcon()
|
||||
{
|
||||
return $this->icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set name
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set title
|
||||
*
|
||||
* @param string $title
|
||||
*/
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Link
|
||||
*
|
||||
* @param string $link
|
||||
*/
|
||||
public function setLink($link)
|
||||
{
|
||||
$this->link = $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Link
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLink()
|
||||
{
|
||||
return $this->link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Description
|
||||
*
|
||||
* @param string $description
|
||||
*/
|
||||
public function setDescription($description)
|
||||
{
|
||||
$this->description = $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Navigation Component Id
|
||||
*
|
||||
* @param string $navigationComponentId
|
||||
*/
|
||||
public function setNavigationComponentId($navigationComponentId)
|
||||
{
|
||||
$this->navigationComponentId = $navigationComponentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Navigation Component Id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNavigationComponentId()
|
||||
{
|
||||
return $this->navigationComponentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $navigationFrameScript
|
||||
*/
|
||||
public function setNavigationFrameScript($navigationFrameScript)
|
||||
{
|
||||
$this->navigationFrameScript = $navigationFrameScript;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getNavigationFrameScript()
|
||||
{
|
||||
return $this->navigationFrameScript;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $navigationFrameScriptParameters
|
||||
*/
|
||||
public function setNavigationFrameScriptParameters($navigationFrameScriptParameters)
|
||||
{
|
||||
$this->navigationFrameScriptParameters = $navigationFrameScriptParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getNavigationFrameScriptParameters()
|
||||
{
|
||||
return $this->navigationFrameScriptParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set onClick
|
||||
*
|
||||
* @param string $onClick
|
||||
*/
|
||||
public function setOnClick($onClick)
|
||||
{
|
||||
$this->onClick = $onClick;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get onClick
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOnClick()
|
||||
{
|
||||
return $this->onClick;
|
||||
}
|
||||
|
||||
public function setCollapsed(bool $collapsed): void
|
||||
{
|
||||
$this->collapsed = $collapsed;
|
||||
}
|
||||
|
||||
public function getCollapsed(): bool
|
||||
{
|
||||
return $this->collapsed;
|
||||
}
|
||||
}
|
||||
+264
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace TYPO3\CMS\Backend\Domain\Repository\Localization;
|
||||
|
||||
/*
|
||||
* 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\Driver\Statement;
|
||||
use TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Repository for record localizations
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class LocalizationRepository
|
||||
{
|
||||
/**
|
||||
* @var TranslationConfigurationProvider
|
||||
*/
|
||||
protected $translationConfigurationProvider;
|
||||
|
||||
public function __construct(TranslationConfigurationProvider $translationConfigurationProvider = null)
|
||||
{
|
||||
$this->translationConfigurationProvider = $translationConfigurationProvider ?? GeneralUtility::makeInstance(TranslationConfigurationProvider::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the language from which the records in a certain language were initially localized
|
||||
*
|
||||
* @param int $pageId
|
||||
* @param int $localizedLanguage
|
||||
* @return array
|
||||
*/
|
||||
public function fetchOriginLanguage(int $pageId, int $localizedLanguage): array
|
||||
{
|
||||
$queryBuilder = $this->getQueryBuilderWithWorkspaceRestriction('tt_content');
|
||||
|
||||
$queryBuilder->select('tt_content_orig.sys_language_uid')
|
||||
->from('tt_content')
|
||||
->join(
|
||||
'tt_content',
|
||||
'tt_content',
|
||||
'tt_content_orig',
|
||||
$queryBuilder->expr()->eq(
|
||||
'tt_content.l10n_source',
|
||||
$queryBuilder->quoteIdentifier('tt_content_orig.uid')
|
||||
)
|
||||
)
|
||||
->where(
|
||||
$queryBuilder->expr()->eq(
|
||||
'tt_content.pid',
|
||||
$queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
|
||||
),
|
||||
$queryBuilder->expr()->eq(
|
||||
'tt_content.sys_language_uid',
|
||||
$queryBuilder->createNamedParameter($localizedLanguage, \PDO::PARAM_INT)
|
||||
),
|
||||
$queryBuilder->expr()->neq(
|
||||
'tt_content_orig.sys_language_uid',
|
||||
$queryBuilder->createNamedParameter(-1, \PDO::PARAM_INT)
|
||||
)
|
||||
)
|
||||
->groupBy('tt_content_orig.sys_language_uid');
|
||||
$this->getAllowedLanguageConstraintsForBackendUser($pageId, $queryBuilder, $this->getBackendUser(), 'tt_content_orig');
|
||||
|
||||
return $queryBuilder->execute()->fetch() ?: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of localized records in given page and language
|
||||
* Records which were added to the language directly (not through translation) are not counted.
|
||||
*
|
||||
* @param int $pageId
|
||||
* @param int $languageId
|
||||
* @return int
|
||||
*/
|
||||
public function getLocalizedRecordCount(int $pageId, int $languageId): int
|
||||
{
|
||||
$queryBuilder = $this->getQueryBuilderWithWorkspaceRestriction('tt_content');
|
||||
|
||||
$rowCount = $queryBuilder->count('uid')
|
||||
->from('tt_content')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq(
|
||||
'sys_language_uid',
|
||||
$queryBuilder->createNamedParameter($languageId, \PDO::PARAM_INT)
|
||||
),
|
||||
$queryBuilder->expr()->eq(
|
||||
'pid',
|
||||
$queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
|
||||
),
|
||||
$queryBuilder->expr()->neq(
|
||||
'l10n_source',
|
||||
$queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
|
||||
)
|
||||
)
|
||||
->execute()
|
||||
->fetchColumn(0);
|
||||
|
||||
return (int)$rowCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all available languages
|
||||
*
|
||||
* @param int $pageId
|
||||
* @param int $languageId
|
||||
* @return array
|
||||
*/
|
||||
public function fetchAvailableLanguages(int $pageId, int $languageId): array
|
||||
{
|
||||
$queryBuilder = $this->getQueryBuilderWithWorkspaceRestriction('tt_content');
|
||||
$queryBuilder->select('sys_language_uid')
|
||||
->from('tt_content')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq(
|
||||
'pid',
|
||||
$queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
|
||||
),
|
||||
$queryBuilder->expr()->neq(
|
||||
'sys_language_uid',
|
||||
$queryBuilder->createNamedParameter($languageId, \PDO::PARAM_INT)
|
||||
)
|
||||
)
|
||||
->groupBy('sys_language_uid');
|
||||
|
||||
$this->getAllowedLanguageConstraintsForBackendUser($pageId, $queryBuilder, $this->getBackendUser());
|
||||
$languages = $queryBuilder->execute()->fetchAll();
|
||||
return $languages ?: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds additional query constraints to exclude hidden languages and
|
||||
* limit a backend user to its allowed languages (unless the user is an admin)
|
||||
*
|
||||
* @param int $pageId
|
||||
* @param QueryBuilder $queryBuilder
|
||||
* @param BackendUserAuthentication $backendUser
|
||||
* @param string $alias
|
||||
*/
|
||||
protected function getAllowedLanguageConstraintsForBackendUser(int $pageId, QueryBuilder $queryBuilder, BackendUserAuthentication $backendUser, string $alias = ''): void
|
||||
{
|
||||
if ($backendUser->isAdmin()) {
|
||||
return;
|
||||
}
|
||||
// This always includes default language
|
||||
$allowedLanguages = $this->translationConfigurationProvider->getSystemLanguages($pageId);
|
||||
$queryBuilder->andWhere(
|
||||
$queryBuilder->expr()->in(
|
||||
($alias === '' ? '' : ($alias . '.')) . 'sys_language_uid',
|
||||
$queryBuilder->createNamedParameter(array_keys($allowedLanguages), Connection::PARAM_INT_ARRAY)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get records for copy process
|
||||
*
|
||||
* @param int $pageId
|
||||
* @param int $destLanguageId
|
||||
* @param int $languageId
|
||||
* @param string $fields
|
||||
* @return Statement
|
||||
*/
|
||||
public function getRecordsToCopyDatabaseResult(int $pageId, int $destLanguageId, int $languageId, string $fields = '*'): Statement
|
||||
{
|
||||
$originalUids = [];
|
||||
|
||||
// Get original uid of existing elements triggered language
|
||||
$queryBuilder = $this->getQueryBuilderWithWorkspaceRestriction('tt_content');
|
||||
|
||||
$originalUidsStatement = $queryBuilder
|
||||
->select('l10n_source')
|
||||
->from('tt_content')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq(
|
||||
'sys_language_uid',
|
||||
$queryBuilder->createNamedParameter($destLanguageId, \PDO::PARAM_INT)
|
||||
),
|
||||
$queryBuilder->expr()->eq(
|
||||
'pid',
|
||||
$queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
|
||||
)
|
||||
)
|
||||
->execute();
|
||||
|
||||
while ($origUid = $originalUidsStatement->fetchColumn(0)) {
|
||||
$originalUids[] = (int)$origUid;
|
||||
}
|
||||
|
||||
$queryBuilder->select(...GeneralUtility::trimExplode(',', $fields, true))
|
||||
->from('tt_content')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq(
|
||||
'sys_language_uid',
|
||||
$queryBuilder->createNamedParameter($languageId, \PDO::PARAM_INT)
|
||||
),
|
||||
$queryBuilder->expr()->eq(
|
||||
'pid',
|
||||
$queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
|
||||
)
|
||||
)
|
||||
->orderBy('sorting');
|
||||
|
||||
if (!empty($originalUids)) {
|
||||
$queryBuilder
|
||||
->andWhere(
|
||||
$queryBuilder->expr()->notIn(
|
||||
'uid',
|
||||
$queryBuilder->createNamedParameter($originalUids, Connection::PARAM_INT_ARRAY)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $queryBuilder->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current BE user.
|
||||
*
|
||||
* @return BackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUser(): BackendUserAuthentication
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a QueryBuilder for the given table with preconfigured restrictions
|
||||
* to not retrieve workspace placeholders or deleted records.
|
||||
*
|
||||
* @param string $tableName
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
protected function getQueryBuilderWithWorkspaceRestriction(string $tableName): QueryBuilder
|
||||
{
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($tableName);
|
||||
$queryBuilder->getRestrictions()
|
||||
->removeAll()
|
||||
->add(GeneralUtility::makeInstance(DeletedRestriction::class))
|
||||
->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Backend\Domain\Repository\Module;
|
||||
|
||||
/*
|
||||
* 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\Module\ModuleLoader;
|
||||
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Imaging\IconFactory;
|
||||
use TYPO3\CMS\Core\Imaging\IconRegistry;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Repository for backend module menu
|
||||
* compiles all data from $GLOBALS[TBE_MODULES]
|
||||
*/
|
||||
class BackendModuleRepository implements \TYPO3\CMS\Core\SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var \TYPO3\CMS\Backend\Module\ModuleStorage
|
||||
*/
|
||||
protected $moduleStorage;
|
||||
|
||||
/**
|
||||
* Constructs the module menu and gets the Singleton instance of the menu
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->moduleStorage = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Module\ModuleStorage::class);
|
||||
|
||||
$rawData = $this->getRawModuleMenuData();
|
||||
|
||||
$this->convertRawModuleDataToModuleMenuObject($rawData);
|
||||
$this->createMenuEntriesForTbeModulesExt();
|
||||
}
|
||||
|
||||
/**
|
||||
* loads all module information in the module storage
|
||||
*
|
||||
* @param array $excludeGroupNames
|
||||
* @return \SplObjectStorage
|
||||
*/
|
||||
public function loadAllowedModules(array $excludeGroupNames = [])
|
||||
{
|
||||
if (empty($excludeGroupNames)) {
|
||||
return $this->moduleStorage->getEntries();
|
||||
}
|
||||
|
||||
$modules = new \SplObjectStorage();
|
||||
foreach ($this->moduleStorage->getEntries() as $moduleGroup) {
|
||||
if (!in_array($moduleGroup->getName(), $excludeGroupNames, true)) {
|
||||
if ($moduleGroup->getChildren()->count() > 0) {
|
||||
$modules->attach($moduleGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $groupName
|
||||
* @return \SplObjectStorage|false
|
||||
**/
|
||||
public function findByGroupName($groupName = '')
|
||||
{
|
||||
foreach ($this->moduleStorage->getEntries() as $moduleGroup) {
|
||||
if ($moduleGroup->getName() === $groupName) {
|
||||
return $moduleGroup;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a module menu entry by name
|
||||
*
|
||||
* @param string $name
|
||||
* @return \TYPO3\CMS\Backend\Domain\Model\Module\BackendModule|bool
|
||||
*/
|
||||
public function findByModuleName($name)
|
||||
{
|
||||
$entries = $this->moduleStorage->getEntries();
|
||||
$entry = $this->findByModuleNameInGivenEntries($name, $entries);
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a module menu entry by name in a given storage
|
||||
*
|
||||
* @param string $name
|
||||
* @param \SplObjectStorage $entries
|
||||
* @return \TYPO3\CMS\Backend\Domain\Model\Module\BackendModule|bool
|
||||
*/
|
||||
public function findByModuleNameInGivenEntries($name, \SplObjectStorage $entries)
|
||||
{
|
||||
foreach ($entries as $entry) {
|
||||
if ($entry->getName() === $name) {
|
||||
return $entry;
|
||||
}
|
||||
$children = $entry->getChildren();
|
||||
if (!empty($children)) {
|
||||
$childRecord = $this->findByModuleNameInGivenEntries($name, $children);
|
||||
if ($childRecord !== false) {
|
||||
return $childRecord;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the module menu object structure from the raw data array
|
||||
*
|
||||
* @param array $rawModuleData
|
||||
*/
|
||||
protected function convertRawModuleDataToModuleMenuObject(array $rawModuleData)
|
||||
{
|
||||
foreach ($rawModuleData as $module) {
|
||||
$entry = $this->createEntryFromRawData($module);
|
||||
if (isset($module['subitems']) && !empty($module['subitems'])) {
|
||||
foreach ($module['subitems'] as $subitem) {
|
||||
$subEntry = $this->createEntryFromRawData($subitem);
|
||||
$entry->addChild($subEntry);
|
||||
}
|
||||
}
|
||||
$this->moduleStorage->attachEntry($entry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a menu entry object from an array
|
||||
*
|
||||
* @param array $module
|
||||
* @return \TYPO3\CMS\Backend\Domain\Model\Module\BackendModule
|
||||
*/
|
||||
protected function createEntryFromRawData(array $module)
|
||||
{
|
||||
/** @var \TYPO3\CMS\Backend\Domain\Model\Module\BackendModule $entry */
|
||||
$entry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Domain\Model\Module\BackendModule::class);
|
||||
if (!empty($module['name']) && is_string($module['name'])) {
|
||||
$entry->setName($module['name']);
|
||||
}
|
||||
if (!empty($module['title']) && is_string($module['title'])) {
|
||||
$entry->setTitle($this->getLanguageService()->sL($module['title']));
|
||||
}
|
||||
if (!empty($module['onclick']) && is_string($module['onclick'])) {
|
||||
$entry->setOnClick($module['onclick']);
|
||||
}
|
||||
if (!empty($module['link']) && is_string($module['link'])) {
|
||||
$entry->setLink($module['link']);
|
||||
} elseif (empty($module['link']) && !empty($module['path']) && is_string($module['path'])) {
|
||||
$entry->setLink($module['path']);
|
||||
}
|
||||
if (!empty($module['description']) && is_string($module['description'])) {
|
||||
$entry->setDescription($this->getLanguageService()->sL($module['description']));
|
||||
}
|
||||
if (!empty($module['icon'])) {
|
||||
$entry->setIcon($module['icon']);
|
||||
}
|
||||
if (!empty($module['navigationComponentId']) && is_string($module['navigationComponentId'])) {
|
||||
$entry->setNavigationComponentId($module['navigationComponentId']);
|
||||
}
|
||||
if (!empty($module['navigationFrameScript']) && is_string($module['navigationFrameScript'])) {
|
||||
$entry->setNavigationFrameScript($module['navigationFrameScript']);
|
||||
} elseif (!empty($module['parentNavigationFrameScript']) && is_string($module['parentNavigationFrameScript'])) {
|
||||
$entry->setNavigationFrameScript($module['parentNavigationFrameScript']);
|
||||
}
|
||||
if (!empty($module['navigationFrameScriptParam']) && is_string($module['navigationFrameScriptParam'])) {
|
||||
$entry->setNavigationFrameScriptParameters($module['navigationFrameScriptParam']);
|
||||
}
|
||||
$moduleMenuState = json_decode($this->getBackendUser()->uc['modulemenu'] ?? '{}', true);
|
||||
$entry->setCollapsed(isset($moduleMenuState[$module['name']]));
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the "third level" menu entries (submodules for the info module for
|
||||
* example) from the TBE_MODULES_EXT array
|
||||
*/
|
||||
protected function createMenuEntriesForTbeModulesExt()
|
||||
{
|
||||
foreach ($GLOBALS['TBE_MODULES_EXT'] ?? [] as $mainModule => $tbeModuleExt) {
|
||||
list($main) = explode('_', $mainModule);
|
||||
$mainEntry = $this->findByModuleName($main);
|
||||
if ($mainEntry === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$subEntries = $mainEntry->getChildren();
|
||||
if (empty($subEntries)) {
|
||||
continue;
|
||||
}
|
||||
$matchingSubEntry = $this->findByModuleName($mainModule);
|
||||
if ($matchingSubEntry !== false) {
|
||||
if (isset($tbeModuleExt['MOD_MENU']) && isset($tbeModuleExt['MOD_MENU']['function'])) {
|
||||
foreach ($tbeModuleExt['MOD_MENU']['function'] as $subModule) {
|
||||
$entry = $this->createEntryFromRawData($subModule);
|
||||
$matchingSubEntry->addChild($entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* loads the module menu from the moduleloader based on $GLOBALS['TBE_MODULES']
|
||||
* and compiles an array with all the data needed for menu etc.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getRawModuleMenuData()
|
||||
{
|
||||
// Loads the backend modules available for the logged in user.
|
||||
/** @var ModuleLoader $moduleLoader */
|
||||
$moduleLoader = GeneralUtility::makeInstance(ModuleLoader::class);
|
||||
$moduleLoader->observeWorkspaces = true;
|
||||
$moduleLoader->load($GLOBALS['TBE_MODULES']);
|
||||
$loadedModules = $moduleLoader->modules;
|
||||
|
||||
$modules = [];
|
||||
|
||||
// Unset modules that are meant to be hidden from the menu.
|
||||
$loadedModules = $this->removeHiddenModules($loadedModules);
|
||||
$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
|
||||
$dummyScript = (string)$uriBuilder->buildUriFromRoute('dummy');
|
||||
foreach ($loadedModules as $moduleName => $moduleData) {
|
||||
$moduleLink = '';
|
||||
if (!is_array($moduleData['sub'])) {
|
||||
$moduleLink = $moduleData['script'];
|
||||
}
|
||||
$moduleLink = GeneralUtility::resolveBackPath($moduleLink);
|
||||
$moduleLabels = $moduleLoader->getLabelsForModule($moduleName);
|
||||
$moduleKey = 'modmenu_' . $moduleName;
|
||||
$modules[$moduleKey] = [
|
||||
'name' => $moduleName,
|
||||
'title' => $moduleLabels['title'],
|
||||
'onclick' => 'top.goToModule(' . GeneralUtility::quoteJSvalue($moduleName) . ');',
|
||||
'icon' => $this->getModuleIcon($moduleKey, $moduleData),
|
||||
'link' => $moduleLink,
|
||||
'description' => $moduleLabels['shortdescription']
|
||||
];
|
||||
if (!is_array($moduleData['sub']) && $moduleData['script'] !== $dummyScript) {
|
||||
// Work around for modules with own main entry, but being self the only submodule
|
||||
$modules[$moduleKey]['subitems'][$moduleKey] = [
|
||||
'name' => $moduleName,
|
||||
'title' => $moduleLabels['title'],
|
||||
'onclick' => 'top.goToModule(' . GeneralUtility::quoteJSvalue($moduleName) . ');',
|
||||
'icon' => $this->getModuleIcon($moduleKey, $moduleData),
|
||||
'link' => $moduleLink,
|
||||
'originalLink' => $moduleLink,
|
||||
'description' => $moduleLabels['shortdescription'],
|
||||
'navigationFrameScript' => null,
|
||||
'navigationFrameScriptParam' => null,
|
||||
'navigationComponentId' => null
|
||||
];
|
||||
} elseif (is_array($moduleData['sub'])) {
|
||||
foreach ($moduleData['sub'] as $submoduleName => $submoduleData) {
|
||||
if (isset($submoduleData['script'])) {
|
||||
$submoduleLink = GeneralUtility::resolveBackPath($submoduleData['script']);
|
||||
} else {
|
||||
$submoduleLink = (string)$uriBuilder->buildUriFromRoute($submoduleData['name']);
|
||||
}
|
||||
$submoduleKey = $moduleName . '_' . $submoduleName;
|
||||
$submoduleLabels = $moduleLoader->getLabelsForModule($submoduleKey);
|
||||
$submoduleDescription = $submoduleLabels['shortdescription'];
|
||||
$originalLink = $submoduleLink;
|
||||
$navigationFrameScript = $submoduleData['navFrameScript'];
|
||||
$modules[$moduleKey]['subitems'][$submoduleKey] = [
|
||||
'name' => $moduleName . '_' . $submoduleName,
|
||||
'title' => $submoduleLabels['title'],
|
||||
'onclick' => 'top.goToModule(' . GeneralUtility::quoteJSvalue($moduleName . '_' . $submoduleName) . ');',
|
||||
'icon' => $this->getModuleIcon($moduleKey, $submoduleData),
|
||||
'link' => $submoduleLink,
|
||||
'originalLink' => $originalLink,
|
||||
'description' => $submoduleDescription,
|
||||
'navigationFrameScript' => $navigationFrameScript,
|
||||
'navigationFrameScriptParam' => $submoduleData['navFrameScriptParam'],
|
||||
'navigationComponentId' => $submoduleData['navigationComponentId']
|
||||
];
|
||||
// if the main module has a navframe script, inherit to the submodule,
|
||||
// but only if it is not disabled explicitly (option is set to FALSE)
|
||||
if ($moduleData['navFrameScript'] && $submoduleData['inheritNavigationComponentFromMainModule'] !== false) {
|
||||
$modules[$moduleKey]['subitems'][$submoduleKey]['parentNavigationFrameScript'] = $moduleData['navFrameScript'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads User configuration from options.hideModules and removes
|
||||
* modules accordingly.
|
||||
*
|
||||
* @param array $loadedModules
|
||||
* @return array
|
||||
*/
|
||||
protected function removeHiddenModules($loadedModules)
|
||||
{
|
||||
$userTsConfig = $this->getBackendUser()->getTSConfig();
|
||||
|
||||
// Hide modules if set in userTS.
|
||||
$hiddenMainModules = GeneralUtility::trimExplode(',', $userTsConfig['options.']['hideModules'] ?? '', true);
|
||||
foreach ($hiddenMainModules as $hiddenMainModule) {
|
||||
unset($loadedModules[$hiddenMainModule]);
|
||||
}
|
||||
|
||||
// Hide sub-modules if set in userTS.
|
||||
$hiddenModules = $userTsConfig['options.']['hideModules.'] ?? [];
|
||||
if (is_array($hiddenModules)) {
|
||||
foreach ($hiddenModules as $mainModuleName => $subModules) {
|
||||
$hiddenSubModules = GeneralUtility::trimExplode(',', $subModules, true);
|
||||
foreach ($hiddenSubModules as $hiddenSubModule) {
|
||||
unset($loadedModules[$mainModuleName]['sub'][$hiddenSubModule]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $loadedModules;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the module icon
|
||||
*
|
||||
* @param string $moduleKey Module key
|
||||
* @param array $moduleData the compiled data associated with it
|
||||
* @return string Icon data, either sprite or <img> tag
|
||||
*/
|
||||
protected function getModuleIcon($moduleKey, $moduleData)
|
||||
{
|
||||
$iconIdentifier = !empty($moduleData['iconIdentifier'])
|
||||
? $moduleData['iconIdentifier']
|
||||
: 'module-icon-' . $moduleKey;
|
||||
$iconRegistry = GeneralUtility::makeInstance(IconRegistry::class);
|
||||
if ($iconRegistry->isRegistered($iconIdentifier)) {
|
||||
$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
|
||||
return $iconFactory->getIcon($iconIdentifier)->render();
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return language service instance
|
||||
*
|
||||
* @return LanguageService
|
||||
*/
|
||||
protected function getLanguageService()
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUser(): BackendUserAuthentication
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,434 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Backend\Domain\Repository;
|
||||
|
||||
/*
|
||||
* 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\Controller\HelpController;
|
||||
use TYPO3\CMS\Backend\Module\ModuleLoader;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Type\File\ImageInfo;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
|
||||
/**
|
||||
* Table manual repository for csh manual handling
|
||||
* @internal This class is a specific Backend repository implementation and is not considered part of the Public TYPO3 API.
|
||||
*/
|
||||
class TableManualRepository
|
||||
{
|
||||
/**
|
||||
* Get the manual of the given table
|
||||
*
|
||||
* @param string $table
|
||||
* @return array the manual for a TCA table, see getItem() for details
|
||||
*/
|
||||
public function getTableManual($table)
|
||||
{
|
||||
$parts = [];
|
||||
|
||||
// Load descriptions for table $table
|
||||
$this->getLanguageService()->loadSingleTableDescription($table);
|
||||
if (is_array($GLOBALS['TCA_DESCR'][$table]['columns']) && $this->checkAccess('tables_select', $table)) {
|
||||
// Reserved for header of table
|
||||
$parts[0] = '';
|
||||
// Traverse table columns as listed in TCA_DESCR
|
||||
foreach ($GLOBALS['TCA_DESCR'][$table]['columns'] as $field => $_) {
|
||||
if (!$this->isExcludableField($table, $field) || $this->checkAccess('non_exclude_fields', $table . ':' . $field)) {
|
||||
if (!$field) {
|
||||
// Header
|
||||
$parts[0] = $this->getItem($table, '', true);
|
||||
} else {
|
||||
// Field
|
||||
$parts[] = $this->getItem($table, $field, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$parts[0]) {
|
||||
unset($parts[0]);
|
||||
}
|
||||
}
|
||||
return $parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single manual
|
||||
*
|
||||
* @param string $table table name
|
||||
* @param string $field field name
|
||||
* @return array
|
||||
*/
|
||||
public function getSingleManual($table, $field)
|
||||
{
|
||||
$this->getLanguageService()->loadSingleTableDescription($table);
|
||||
return $this->getItem($table, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get TOC sections
|
||||
*
|
||||
* @param int $mode e.g. HelpController::TOC_ONLY
|
||||
* @return array
|
||||
*/
|
||||
public function getSections($mode)
|
||||
{
|
||||
// Initialize
|
||||
$cshKeys = array_flip(array_keys($GLOBALS['TCA_DESCR']));
|
||||
$tcaKeys = array_keys($GLOBALS['TCA']);
|
||||
$outputSections = [];
|
||||
$tocArray = [];
|
||||
// TYPO3 Core Features
|
||||
$lang = $this->getLanguageService();
|
||||
$lang->loadSingleTableDescription('xMOD_csh_corebe');
|
||||
$this->renderTableOfContentItem($mode, 'xMOD_csh_corebe', 'core', $outputSections, $tocArray, $cshKeys);
|
||||
// Backend Modules
|
||||
$loadModules = GeneralUtility::makeInstance(ModuleLoader::class);
|
||||
$loadModules->load($GLOBALS['TBE_MODULES']);
|
||||
foreach ($loadModules->modules as $mainMod => $info) {
|
||||
$cshKey = '_MOD_' . $mainMod;
|
||||
if ($cshKeys[$cshKey]) {
|
||||
$lang->loadSingleTableDescription($cshKey);
|
||||
$this->renderTableOfContentItem($mode, $cshKey, 'modules', $outputSections, $tocArray, $cshKeys);
|
||||
}
|
||||
if (is_array($info['sub'])) {
|
||||
foreach ($info['sub'] as $subMod => $subInfo) {
|
||||
$cshKey = '_MOD_' . $mainMod . '_' . $subMod;
|
||||
if ($cshKeys[$cshKey]) {
|
||||
$lang->loadSingleTableDescription($cshKey);
|
||||
$this->renderTableOfContentItem($mode, $cshKey, 'modules', $outputSections, $tocArray, $cshKeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Database Tables
|
||||
foreach ($tcaKeys as $table) {
|
||||
// Load descriptions for table $table
|
||||
$lang->loadSingleTableDescription($table);
|
||||
if (is_array($GLOBALS['TCA_DESCR'][$table]['columns']) && $this->checkAccess('tables_select', $table)) {
|
||||
$this->renderTableOfContentItem($mode, $table, 'tables', $outputSections, $tocArray, $cshKeys);
|
||||
}
|
||||
}
|
||||
foreach ($cshKeys as $cshKey => $value) {
|
||||
// Extensions
|
||||
if (GeneralUtility::isFirstPartOfStr($cshKey, 'xEXT_') && !isset($GLOBALS['TCA'][$cshKey])) {
|
||||
$lang->loadSingleTableDescription($cshKey);
|
||||
$this->renderTableOfContentItem($mode, $cshKey, 'extensions', $outputSections, $tocArray, $cshKeys);
|
||||
}
|
||||
// Other
|
||||
if (!GeneralUtility::isFirstPartOfStr($cshKey, '_MOD_') && !isset($GLOBALS['TCA'][$cshKey])) {
|
||||
$lang->loadSingleTableDescription($cshKey);
|
||||
$this->renderTableOfContentItem($mode, $cshKey, 'other', $outputSections, $tocArray, $cshKeys);
|
||||
}
|
||||
}
|
||||
|
||||
if ($mode === HelpController::TOC_ONLY) {
|
||||
return $tocArray;
|
||||
}
|
||||
|
||||
return [
|
||||
'toc' => $tocArray,
|
||||
'content' => $outputSections
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a TOC list element and renders corresponding HELP content if "renderALL" mode is set.
|
||||
*
|
||||
* @param int $mode Mode
|
||||
* @param string $table CSH key / Table name
|
||||
* @param string $tocCat TOC category keyword: "core", "modules", "tables", "other
|
||||
* @param array $outputSections Array for accumulation of rendered HELP Content (in "renderALL" mode). Passed by reference!
|
||||
* @param array $tocArray TOC array; Here TOC index elements are created. Passed by reference!
|
||||
* @param array $CSHkeys CSH keys array. Every item rendered will be unset in this array so finally we can see what CSH keys are not processed yet. Passed by reference!
|
||||
*/
|
||||
protected function renderTableOfContentItem($mode, $table, $tocCat, &$outputSections, &$tocArray, &$CSHkeys)
|
||||
{
|
||||
$tocArray[$tocCat][$table] = $this->getTableFieldLabel($table);
|
||||
if (!$mode) {
|
||||
// Render full manual right here!
|
||||
$outputSections[$table]['content'] = $this->getTableManual($table);
|
||||
if (!$outputSections[$table]) {
|
||||
unset($outputSections[$table]);
|
||||
}
|
||||
}
|
||||
|
||||
// Unset CSH key
|
||||
unset($CSHkeys[$table]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns composite label for table/field
|
||||
*
|
||||
* @param string $key CSH key / table name
|
||||
* @param string $field Sub key / field name
|
||||
* @param string $mergeToken Token to merge the two strings with
|
||||
* @return string Labels joined with merge token
|
||||
* @see getTableFieldNames()
|
||||
*/
|
||||
protected function getTableFieldLabel($key, $field = '', $mergeToken = ': ')
|
||||
{
|
||||
// Get table / field parts
|
||||
list($tableName, $fieldName) = $this->getTableFieldNames($key, $field);
|
||||
// Create label
|
||||
return $this->getLanguageService()->sL($tableName) . ($field ? $mergeToken . rtrim(trim($this->getLanguageService()->sL($fieldName)), ':') : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns labels for a given field in a given structure
|
||||
*
|
||||
* @param string $key CSH key / table name
|
||||
* @param string $field Sub key / field name
|
||||
* @return array Table and field labels in a numeric array
|
||||
*/
|
||||
protected function getTableFieldNames($key, $field)
|
||||
{
|
||||
$this->getLanguageService()->loadSingleTableDescription($key);
|
||||
// Define the label for the key
|
||||
if (!empty($GLOBALS['TCA_DESCR'][$key]['columns']['']['alttitle'])) {
|
||||
// If there's an alternative title, use it
|
||||
$keyName = $GLOBALS['TCA_DESCR'][$key]['columns']['']['alttitle'];
|
||||
} elseif (isset($GLOBALS['TCA'][$key])) {
|
||||
// Otherwise, if it's a table, use its title
|
||||
$keyName = $GLOBALS['TCA'][$key]['ctrl']['title'];
|
||||
} else {
|
||||
// If no title was found, make sure to remove any "_MOD_"
|
||||
$keyName = preg_replace('/^_MOD_/', '', $key);
|
||||
}
|
||||
// Define the label for the field
|
||||
$fieldName = $field;
|
||||
if (!empty($GLOBALS['TCA_DESCR'][$key]['columns'][$field]['alttitle'])) {
|
||||
// If there's an alternative title, use it
|
||||
$fieldName = $GLOBALS['TCA_DESCR'][$key]['columns'][$field]['alttitle'];
|
||||
} elseif (!empty($GLOBALS['TCA'][$key]['columns'][$field])) {
|
||||
// Otherwise, if it's a table, use its title
|
||||
$fieldName = $GLOBALS['TCA'][$key]['columns'][$field]['label'];
|
||||
}
|
||||
return [$keyName, $fieldName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a single $table/$field information piece
|
||||
* If $anchors is set, then seeAlso references to the same table will be page-anchors, not links.
|
||||
*
|
||||
* @param string $table CSH key / table name
|
||||
* @param string $field Sub key / field name
|
||||
* @param bool $anchors If anchors is to be shown.
|
||||
* @return array with the information
|
||||
*/
|
||||
protected function getItem($table, $field, $anchors = false)
|
||||
{
|
||||
if (!empty($table)) {
|
||||
$field = !empty($field) ? $field : '';
|
||||
$setup = $GLOBALS['TCA_DESCR'][$table]['columns'][$field];
|
||||
return [
|
||||
'table' => $table,
|
||||
'field' => $field,
|
||||
'configuration' => $setup,
|
||||
'headerLine' => $this->getTableFieldLabel($table, $field),
|
||||
'content' => !empty($setup['description']) ? $setup['description'] : '',
|
||||
'images' => !empty($setup['image']) ? $this->getImages($setup['image'], $setup['image_descr']) : [],
|
||||
'seeAlso' => !empty($setup['seeAlso']) ? $this->getSeeAlsoLinks($setup['seeAlso'], $anchors ? $table : '') : '',
|
||||
];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get see-also links
|
||||
*
|
||||
* @param string $value See-also input codes
|
||||
* @param string $anchorTable If $anchorTable is set to a tablename, then references to this table will be made as anchors, not URLs.
|
||||
* @return array See-also links
|
||||
*/
|
||||
protected function getSeeAlsoLinks($value, $anchorTable = '')
|
||||
{
|
||||
// Split references by comma or linebreak
|
||||
$items = preg_split('/[,' . LF . ']/', $value);
|
||||
$lines = [];
|
||||
foreach ($items as $itemValue) {
|
||||
$itemValue = trim($itemValue);
|
||||
if ($itemValue) {
|
||||
$reference = GeneralUtility::trimExplode(':', $itemValue);
|
||||
$referenceUrl = GeneralUtility::trimExplode('|', $itemValue);
|
||||
if (strpos($referenceUrl[1], 'http') === 0) {
|
||||
// URL reference
|
||||
$lines[] = [
|
||||
'url' => $referenceUrl[1],
|
||||
'title' => $referenceUrl[0],
|
||||
'target' => '_blank'
|
||||
];
|
||||
} elseif (strpos($referenceUrl[1], 'FILE:') === 0) {
|
||||
// File reference
|
||||
$fileName = GeneralUtility::getFileAbsFileName(substr($referenceUrl[1], 5));
|
||||
if ($fileName && @is_file($fileName)) {
|
||||
$fileName = '../' . PathUtility::stripPathSitePrefix($fileName);
|
||||
$lines[] = [
|
||||
'url' => $fileName,
|
||||
'title' => $referenceUrl[0],
|
||||
'target' => '_blank'
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// Table reference
|
||||
$table = !empty($reference[0]) ? $reference[0] : '';
|
||||
$field = !empty($reference[1]) ? $reference[1] : '';
|
||||
$accessAllowed = true;
|
||||
// Check if table exists and current user can access it
|
||||
if (!empty($table)) {
|
||||
$accessAllowed = !$this->getTableSetup($table) || $this->checkAccess('tables_select', $table);
|
||||
}
|
||||
// Check if field exists and is excludable or user can access it
|
||||
if ($accessAllowed && !empty($field)) {
|
||||
$accessAllowed = !$this->isExcludableField($table, $field) || $this->checkAccess('non_exclude_fields', $table . ':' . $field);
|
||||
}
|
||||
// Check read access
|
||||
if ($accessAllowed && isset($GLOBALS['TCA_DESCR'][$table])) {
|
||||
// Make see-also link
|
||||
$label = $this->getTableFieldLabel($table, $field, ' / ');
|
||||
if ($anchorTable && $table === $anchorTable) {
|
||||
$lines[] = [
|
||||
'url' => '#' . rawurlencode(implode('.', $reference)),
|
||||
'title' => $label,
|
||||
];
|
||||
} else {
|
||||
$lines[] = [
|
||||
'internal' => true,
|
||||
'arguments' => [
|
||||
'table' => $table,
|
||||
'field' => $field,
|
||||
'action' => 'detail',
|
||||
],
|
||||
'title' => $label
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given table / field is excludable
|
||||
*
|
||||
* @param string $table The table
|
||||
* @param string $field The field
|
||||
* @return bool TRUE if given field is excludable
|
||||
*/
|
||||
protected function isExcludableField($table, $field)
|
||||
{
|
||||
$fieldSetup = $this->getFieldSetup($table, $field);
|
||||
if (!empty($fieldSetup)) {
|
||||
return !empty($fieldSetup['exclude']);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of images with description
|
||||
*
|
||||
* @param string $images Image file reference (list of)
|
||||
* @param string $descriptions Description string (divided for each image by line break)
|
||||
* @return array
|
||||
*/
|
||||
protected function getImages($images, $descriptions)
|
||||
{
|
||||
$imageData = [];
|
||||
// Splitting
|
||||
$imgArray = GeneralUtility::trimExplode(',', $images, true);
|
||||
if (!empty($imgArray)) {
|
||||
$descrArray = explode(LF, $descriptions, count($imgArray));
|
||||
foreach ($imgArray as $k => $image) {
|
||||
$descriptions = $descrArray[$k];
|
||||
$absImagePath = GeneralUtility::getFileAbsFileName($image);
|
||||
if ($absImagePath && @is_file($absImagePath)) {
|
||||
$imgFile = PathUtility::stripPathSitePrefix($absImagePath);
|
||||
$imageInfo = GeneralUtility::makeInstance(ImageInfo::class, $absImagePath);
|
||||
if ($imageInfo->getWidth()) {
|
||||
$imageData[] = [
|
||||
'image' => $imgFile,
|
||||
'description' => $descriptions
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $imageData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the setup for given table
|
||||
*
|
||||
* @param string $table The table
|
||||
* @return array The table setup
|
||||
*/
|
||||
protected function getTableSetup($table)
|
||||
{
|
||||
if (!empty($table) && !empty($GLOBALS['TCA'][$table])) {
|
||||
return $GLOBALS['TCA'][$table];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the setup for given table / field
|
||||
*
|
||||
* @param string $table The table
|
||||
* @param string $field The field
|
||||
* @param bool $allowEmptyField Allow empty field
|
||||
* @return array The field setup
|
||||
*/
|
||||
protected function getFieldSetup($table, $field, $allowEmptyField = false)
|
||||
{
|
||||
$tableSetup = $this->getTableSetup($table);
|
||||
if (!empty($tableSetup) && (!empty($field) || $allowEmptyField) && !empty($tableSetup['columns'][$field])) {
|
||||
return $tableSetup['columns'][$field];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current backend user has access to given identifier
|
||||
*
|
||||
* @param string $type The type
|
||||
* @param string $identifier The search string in access list
|
||||
* @return bool TRUE if the user has access
|
||||
*/
|
||||
protected function checkAccess($type, $identifier)
|
||||
{
|
||||
if (!empty($type) && !empty($identifier)) {
|
||||
return $this->getBackendUser()->check($type, $identifier);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current BE user.
|
||||
*
|
||||
* @return BackendUserAuthentication
|
||||
*/
|
||||
protected function getBackendUser(): BackendUserAuthentication
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns LanguageService
|
||||
*
|
||||
* @return \TYPO3\CMS\Core\Localization\LanguageService
|
||||
*/
|
||||
protected function getLanguageService()
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user