TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Backend\Controller;
|
||||
|
||||
use Psr\Http\Message\ResponseFactoryInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Backend\Attribute\AsController;
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Backend\View\BackendViewFactory;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Schema\Capability\TcaSchemaCapability;
|
||||
use TYPO3\CMS\Core\Schema\TcaSchemaFactory;
|
||||
use TYPO3\CMS\Core\View\ViewInterface;
|
||||
|
||||
/**
|
||||
* Controller for handling the display column selection for records, typically executed from list modules.
|
||||
*
|
||||
* @internal This class is a specific Backend controller implementation and is not part of the TYPO3's Core API.
|
||||
*/
|
||||
#[AsController]
|
||||
readonly class ColumnSelectorController
|
||||
{
|
||||
private const array PSEUDO_FIELDS = ['_REF_', '_PATH_'];
|
||||
private const array EXCLUDE_FILE_FIELDS = [
|
||||
'pid', // Not relevant as all records are on pid=0
|
||||
'identifier', // Handled manually in listing
|
||||
'name', // Handled manually in listing
|
||||
'metadata', // The reference to the meta data is not relevant
|
||||
'file', // The reference to the file is not relevant
|
||||
'sys_language_uid', // Not relevant in listing since only default is displayed
|
||||
'l10n_parent', // Not relevant in listing
|
||||
't3ver_state', // Not relevant in listing
|
||||
't3ver_wsid', // Not relevant in listing
|
||||
't3ver_oid', // Not relevant in listing
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
protected ResponseFactoryInterface $responseFactory,
|
||||
protected BackendViewFactory $backendViewFactory,
|
||||
protected TcaSchemaFactory $tcaSchemaFactory,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Update the columns to be displayed for the given table
|
||||
*/
|
||||
public function updateVisibleColumnsAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$parsedBody = $request->getParsedBody();
|
||||
$table = (string)($parsedBody['table'] ?? '');
|
||||
$selectedColumns = $parsedBody['selectedColumns'] ?? [];
|
||||
|
||||
if ($table === '' || !is_array($selectedColumns)) {
|
||||
return $this->jsonResponse([
|
||||
'success' => false,
|
||||
'message' => htmlspecialchars(
|
||||
$this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_column_selector.xlf:updateColumnView.nothingUpdated')
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
$backendUser = $this->getBackendUserAuthentication();
|
||||
$displayFields = $backendUser->getModuleData('list/displayFields');
|
||||
$displayFields[$table] = $selectedColumns;
|
||||
$backendUser->pushModuleData('list/displayFields', $displayFields);
|
||||
|
||||
return $this->jsonResponse(['success' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the show columns selector form
|
||||
*/
|
||||
public function showColumnsSelectorAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$queryParams = $request->getQueryParams();
|
||||
$table = (string)($queryParams['table'] ?? '');
|
||||
|
||||
if ($table === '') {
|
||||
throw new \RuntimeException('No table was given for selecting columns', 1625169125);
|
||||
}
|
||||
$view = $this->backendViewFactory->create($request);
|
||||
$view->assignMultiple([
|
||||
'table' => $table,
|
||||
'columns' => $this->getColumns($table, (int)($queryParams['id'] ?? 0)),
|
||||
]);
|
||||
|
||||
return $this->htmlResponse($view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all columns for the table, which can be selected
|
||||
*/
|
||||
protected function getColumns(string $table, int $pageId): array
|
||||
{
|
||||
$tsConfig = BackendUtility::getPagesTSconfig($pageId);
|
||||
|
||||
// Current fields selection
|
||||
$displayFields = $this->getBackendUserAuthentication()->getModuleData('list/displayFields')[$table] ?? [];
|
||||
|
||||
if ($table === '_FILE') {
|
||||
// Special handling for _FILE (merging sys_file and sys_file_metadata together)
|
||||
$fields = $this->getFileFields();
|
||||
} else {
|
||||
// Request fields from table and add pseudo fields
|
||||
$fields = array_merge(BackendUtility::getAllowedFieldsForTable($table), self::PSEUDO_FIELDS);
|
||||
}
|
||||
|
||||
$columns = $specialColumns = $disabledColumns = [];
|
||||
foreach ($fields as $fieldName) {
|
||||
$concreteTableName = $table;
|
||||
|
||||
// In case we deal with _FILE, the field name is prefixed with the
|
||||
// concrete table name, which is either sys_file or sys_file_metadata.
|
||||
if ($table === '_FILE') {
|
||||
[$concreteTableName, $fieldName] = explode('|', $fieldName);
|
||||
}
|
||||
|
||||
// Hide field if disabled
|
||||
if ($tsConfig['TCEFORM.'][$concreteTableName . '.'][$fieldName . '.']['disabled'] ?? false) {
|
||||
continue;
|
||||
}
|
||||
$schema = $this->tcaSchemaFactory->get($concreteTableName);
|
||||
$labelFieldName = false;
|
||||
if ($schema->hasCapability(TcaSchemaCapability::Label)) {
|
||||
$labelFieldName = $schema->getCapability(TcaSchemaCapability::Label)->getPrimaryFieldName();
|
||||
}
|
||||
|
||||
// Determine if the column should be disabled (Meaning it is always selected and can not be turned off)
|
||||
$isDisabled = $fieldName === $labelFieldName;
|
||||
|
||||
// Determine field label
|
||||
$label = ($schema->hasField($fieldName) ? $schema->getField($fieldName)->getLabel() : '') ?: null;
|
||||
$label = $this->getLanguageService()->translateLabel(
|
||||
$tsConfig['TCEFORM.'][$concreteTableName . '.'][$fieldName . '.']['label.'] ?? [],
|
||||
$tsConfig['TCEFORM.'][$concreteTableName . '.'][$fieldName . '.']['label']
|
||||
?? $label
|
||||
?? 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.' . $fieldName
|
||||
);
|
||||
|
||||
// Add configuration for this column
|
||||
$columnConfiguration = [
|
||||
'name' => $fieldName,
|
||||
'selected' => $isDisabled || in_array($fieldName, $displayFields, true),
|
||||
'disabled' => $isDisabled,
|
||||
'pseudo' => in_array($fieldName, self::PSEUDO_FIELDS, true),
|
||||
'label' => $label,
|
||||
];
|
||||
|
||||
// Add column configuration to the correct group
|
||||
if ($columnConfiguration['disabled']) {
|
||||
$disabledColumns[] = $columnConfiguration;
|
||||
} elseif (!$columnConfiguration['label']) {
|
||||
$specialColumns[] = $columnConfiguration;
|
||||
} else {
|
||||
$columns[] = $columnConfiguration;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort standard columns by their resolved label
|
||||
usort($columns, static fn($a, $b) => $a['label'] <=> $b['label']);
|
||||
|
||||
// Disabled columns go first, followed by standard columns
|
||||
// and special columns, which do not have a label.
|
||||
return array_merge($disabledColumns, $columns, $specialColumns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file related fields by merging sys_file and sys_file_metadata together
|
||||
* and adding the corresponding table as prefix (needed for labels processing).
|
||||
*/
|
||||
protected function getFileFields(): array
|
||||
{
|
||||
// Get all sys_file fields expect excluded ones
|
||||
$fileFields = array_filter(
|
||||
BackendUtility::getAllowedFieldsForTable('sys_file'),
|
||||
static fn(string $field): bool => !in_array($field, self::EXCLUDE_FILE_FIELDS, true)
|
||||
);
|
||||
|
||||
// Always add crdate and tstamp fields for files
|
||||
$fileFields = array_unique(array_merge($fileFields, ['crdate', 'tstamp']));
|
||||
|
||||
// Update the exclude fields with the fields, already added through sys_file, since those take precedence
|
||||
$excludeFields = array_merge($fileFields, self::EXCLUDE_FILE_FIELDS);
|
||||
|
||||
// Get all sys_file_metadata fields expect excluded ones
|
||||
$fileMetaDataFields = array_filter(
|
||||
BackendUtility::getAllowedFieldsForTable('sys_file_metadata'),
|
||||
static fn(string $field): bool => !in_array($field, $excludeFields, true)
|
||||
);
|
||||
|
||||
// Merge sys_file and sys_file_metadata fields together, while adding the table name as prefix
|
||||
return array_merge(
|
||||
array_map(static fn(string $value): string => 'sys_file|' . $value, $fileFields),
|
||||
array_map(static fn(string $value): string => 'sys_file_metadata|' . $value, $fileMetaDataFields),
|
||||
);
|
||||
}
|
||||
|
||||
protected function htmlResponse(ViewInterface $view): ResponseInterface
|
||||
{
|
||||
$response = $this->responseFactory
|
||||
->createResponse()
|
||||
->withHeader('Content-Type', 'text/html; charset=utf-8');
|
||||
$response->getBody()->write($view->render('ColumnSelector'));
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function jsonResponse(array $data): ResponseInterface
|
||||
{
|
||||
$response = $this->responseFactory
|
||||
->createResponse()
|
||||
->withAddedHeader('Content-Type', 'application/json; charset=utf-8');
|
||||
|
||||
$response->getBody()->write(json_encode($data));
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function getBackendUserAuthentication(): BackendUserAuthentication
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
|
||||
protected function getLanguageService(): LanguageService
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user