Commit 1c7826d5 authored by Christian Eßl's avatar Christian Eßl Committed by Daniel Goerz
Browse files

[BUGFIX] Show fields for files/folders in ElementInformationController

The changes made to the ElementInformationController in #88901 had a few
problems and regressions:

- A lot of information for files and folders, that has previously been
shown, was now missing.
- Metadata for files was missing as well, because this information is
saved in a separate table. (sys_file_metadata)

This patch brings back all the lost information. Also, the Metadata of
a file can now be viewed in the ElementInformation window as well.

Resolves: #90441
Related: #88901
Releases: master
Change-Id: Idb710c83b74845e6ec8b6e2dc7c3d906841ea6ea
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/63332


Tested-by: default avatarTYPO3com <noreply@typo3.com>
Tested-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Tested-by: default avatarChristian Eßl <indy.essl@gmail.com>
Tested-by: Daniel Goerz's avatarDaniel Goerz <daniel.goerz@posteo.de>
Reviewed-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Reviewed-by: default avatarChristian Eßl <indy.essl@gmail.com>
Reviewed-by: Daniel Goerz's avatarDaniel Goerz <daniel.goerz@posteo.de>
parent 8a51dc77
......@@ -35,6 +35,7 @@ use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Resource\AbstractFile;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Resource\Index\MetaDataRepository;
use TYPO3\CMS\Core\Resource\Rendering\RendererRegistry;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Type\Bitmask\Permission;
......@@ -342,89 +343,130 @@ class ElementInformationController
*/
protected function getPropertiesForTable(): array
{
$propertiesForTable = [];
$lang = $this->getLanguageService();
$propertiesForTable = [];
$propertiesForTable['extraFields'] = $this->getExtraFields();
$extraFields = [
'uid' => htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:show_item.php.uid'))
];
// Traverse the list of fields to display for the record:
$fieldList = $this->getFieldList($this->table, (int)$this->row['uid']);
if (in_array($this->type, ['folder', 'file'], true)) {
if ($this->type === 'file') {
$extraFields['creation_date'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.creationDate'));
$extraFields['modification_date'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.timestamp'));
if ($this->fileObject->getType() === AbstractFile::FILETYPE_IMAGE) {
$extraFields['width'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.width'));
$extraFields['height'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.height'));
}
foreach ($fieldList as $name) {
$name = trim($name);
$uid = $this->row['uid'];
if (!isset($GLOBALS['TCA'][$this->table]['columns'][$name])) {
continue;
}
$extraFields['storage'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file.storage'));
$extraFields['folder'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:folder'));
} else {
$extraFields['crdate'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.creationDate'));
$extraFields['cruser_id'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.creationUserId'));
$extraFields['tstamp'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.timestamp'));
// check if the special fields are defined in the TCA ctrl section of the table
foreach ($extraFields as $fieldName => $fieldLabel) {
if (isset($GLOBALS['TCA'][$this->table]['ctrl'][$fieldName])) {
$extraFields[$GLOBALS['TCA'][$this->table]['ctrl'][$fieldName]] = $fieldLabel;
} elseif ($fieldName !== 'uid') {
unset($extraFields[$fieldName]);
}
// not a real field -> skip
if ($this->type === 'file' && $name === 'fileinfo') {
continue;
}
$isExcluded = !(!$GLOBALS['TCA'][$this->table]['columns'][$name]['exclude'] || $this->getBackendUser()->check('non_exclude_fields', $this->table . ':' . $name));
if ($isExcluded) {
continue;
}
$label = $lang->sL(BackendUtility::getItemLabel($this->table, $name));
$label = $label ?: $name;
$propertiesForTable['fields'][] = [
'fieldValue' => BackendUtility::getProcessedValue($this->table, $name, $this->row[$name], 0, 0, false, $uid),
'fieldLabel' => htmlspecialchars($label)
];
}
foreach ($extraFields as $name => $fieldLabel) {
$rowValue = '';
$thisRow = [];
if (!isset($this->row[$name])) {
$resourceObject = $this->fileObject ?: $this->folderObject;
if ($name === 'storage') {
$rowValue = $resourceObject->getStorage()->getName();
} elseif ($name === 'folder') {
$rowValue = $resourceObject->getParentFolder()->getReadablePath();
} elseif ($name === 'width') {
$rowValue = $this->fileObject->getProperty('width') . 'px';
} elseif ($name === 'height') {
$rowValue = $this->fileObject->getProperty('height') . 'px';
}
} elseif ($name === 'creation_date' || $name === 'modification_date' || $name === 'tstamp' || $name === 'crdate') {
$rowValue = BackendUtility::datetime($this->row[$name]);
} else {
$rowValue = BackendUtility::getProcessedValueExtra($this->table, $name, $this->row[$name]);
// additional information for folders and files
if ($this->folderObject instanceof Folder || $this->fileObject instanceof File) {
// storage
if ($this->folderObject instanceof Folder) {
$propertiesForTable['fields']['storage'] = [
'fieldValue' => $this->folderObject->getStorage()->getName(),
'fieldLabel' => htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file.storage'))
];
}
$thisRow['value'] = $rowValue;
$thisRow['fieldLabel'] = rtrim($fieldLabel, ':');
// show the backend username who created the issue
if ($name === 'cruser_id' && $rowValue) {
$creatorRecord = BackendUtility::getRecord('be_users', $rowValue);
if ($creatorRecord) {
/** @var Avatar $avatar */
$avatar = GeneralUtility::makeInstance(Avatar::class);
$creatorRecord['icon'] = $avatar->render($creatorRecord);
$thisRow['creatorRecord'] = $creatorRecord;
$thisRow['value'] = '';
// folder
$resourceObject = $this->fileObject ?: $this->folderObject;
$propertiesForTable['fields']['folder'] = [
'fieldValue' => $resourceObject->getParentFolder()->getReadablePath(),
'fieldLabel' => htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:folder'))
];
if ($this->fileObject instanceof File) {
// show file dimensions for images
if ($this->fileObject->getType() === AbstractFile::FILETYPE_IMAGE) {
$propertiesForTable['fields']['width'] = [
'fieldValue' => $this->fileObject->getProperty('width') . 'px',
'fieldLabel' => htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.width'))
];
$propertiesForTable['fields']['height'] = [
'fieldValue' => $this->fileObject->getProperty('height') . 'px',
'fieldLabel' => htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.height'))
];
}
// file size
$propertiesForTable['fields']['size'] = [
'fieldValue' => GeneralUtility::formatSize((int)$this->fileObject->getProperty('size'), htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:byteSizeUnits'))),
'fieldLabel' => $lang->sL(BackendUtility::getItemLabel($this->table, 'size'))
];
// show the metadata of a file as well
$table = 'sys_file_metadata';
$metaDataRepository = GeneralUtility::makeInstance(MetaDataRepository::class);
$metaData = $metaDataRepository->findByFileUid($this->row['uid']);
$allowedFields = $this->getFieldList($table, (int)$metaData['uid']);
foreach ($metaData as $name => $value) {
if (in_array($name, $allowedFields, true)) {
if (!isset($GLOBALS['TCA'][$table]['columns'][$name])) {
continue;
}
$isExcluded = !(!$GLOBALS['TCA'][$table]['columns'][$name]['exclude'] || $this->getBackendUser()->check('non_exclude_fields', $table . ':' . $name));
if ($isExcluded) {
continue;
}
$label = $lang->sL(BackendUtility::getItemLabel($table, $name));
$label = $label ?: $name;
$propertiesForTable['fields'][] = [
'fieldValue' => BackendUtility::getProcessedValue($table, $name, $metaData[$name], 0, 0, false, $metaData['uid']),
'fieldLabel' => htmlspecialchars($label)
];
}
}
}
$propertiesForTable['extraFields'][$name] = $thisRow;
}
// Traverse the list of fields to display for the record:
return $propertiesForTable;
}
/**
* Get the list of fields that should be shown for the given table
*
* @param string $table
* @param int $uid
* @return array
*/
protected function getFieldList(string $table, int $uid): array
{
$formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
$formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
$formDataCompilerInput = [
'command' => 'edit',
'tableName' => $this->table,
'vanillaUid' => (int)$this->row['uid'],
'tableName' => $table,
'vanillaUid' => $uid,
];
try {
$result = $formDataCompiler->compile($formDataCompilerInput);
$fieldList = array_unique(array_values($result['columnsToProcess']));
$ctrlKeysOfUneededFields = ['origUid', 'transOrigPointerField', 'transOrigDiffSourceField'];
foreach ($ctrlKeysOfUneededFields as $field) {
if (($key = array_search($GLOBALS['TCA'][$this->table]['ctrl'][$field], $fieldList)) !== false) {
$ctrlKeysOfUnneededFields = ['origUid', 'transOrigPointerField', 'transOrigDiffSourceField'];
foreach ($ctrlKeysOfUnneededFields as $field) {
if (($key = array_search($GLOBALS['TCA'][$table]['ctrl'][$field], $fieldList, true)) !== false) {
unset($fieldList[$key]);
}
}
......@@ -432,37 +474,67 @@ class ElementInformationController
$fieldList = [];
}
foreach ($fieldList as $name) {
$thisRow = [];
$name = trim($name);
$uid = $this->row['uid'];
$searchFields = GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['searchFields']);
if (!isset($GLOBALS['TCA'][$this->table]['columns'][$name])) {
continue;
}
return array_unique(array_merge($fieldList, $searchFields));
}
// Storage is already handled above
if ($this->type === 'file' && $name === 'storage') {
continue;
}
/**
* Get the extra fields (uid, timestamps, creator) for the table
*
* @return array
*/
protected function getExtraFields(): array
{
$lang = $this->getLanguageService();
$keyLabelPair = [];
$extraFields = [
'uid' => htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:show_item.php.uid'))
];
// format file size as bytes/kilobytes/megabytes
if ($this->type === 'file' && $name === 'size') {
$this->row[$name] = GeneralUtility::formatSize($this->row[$name], htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:byteSizeUnits')));
if (in_array($this->type, ['folder', 'file'], true)) {
if ($this->type === 'file') {
$extraFields['creation_date'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.creationDate'));
$extraFields['modification_date'] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.timestamp'));
}
$isExcluded = !(!$GLOBALS['TCA'][$this->table]['columns'][$name]['exclude'] || $this->getBackendUser()->check('non_exclude_fields', $this->table . ':' . $name));
if ($isExcluded) {
continue;
} else {
foreach (['crdate' => 'creationDate', 'tstamp' => 'timestamp', 'cruser_id' => 'creationUserId'] as $field => $label) {
if (isset($GLOBALS['TCA'][$this->table]['ctrl'][$field])) {
$extraFields[$GLOBALS['TCA'][$this->table]['ctrl'][$field]] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.' . $label));
}
}
$label = $lang->sL(BackendUtility::getItemLabel($this->table, $name));
$label = $label ?: $name;
}
$thisRow['fieldValue'] = BackendUtility::getProcessedValue($this->table, $name, $this->row[$name], 0, 0, false, $uid);
$thisRow['fieldLabel'] = htmlspecialchars($label);
$propertiesForTable['fields'][] = $thisRow;
foreach ($extraFields as $name => $fieldLabel) {
if (in_array($name, ['creation_date', 'modification_date', 'tstamp', 'crdate'], true)) {
$rowValue = BackendUtility::datetime($this->row[$name]);
$keyLabelPair[$name] = [
'value' => $rowValue,
'fieldLabel' => rtrim($fieldLabel, ':'),
'isDatetime' => true,
];
} else {
$rowValue = BackendUtility::getProcessedValueExtra($this->table, $name, $this->row[$name]);
// show the backend username who created the issue
if ($name === 'cruser_id' && $rowValue) {
$creatorRecord = BackendUtility::getRecord('be_users', $rowValue);
if ($creatorRecord) {
/** @var Avatar $avatar */
$avatar = GeneralUtility::makeInstance(Avatar::class);
$creatorRecord['icon'] = $avatar->render($creatorRecord);
$name = 'creatorRecord';
$rowValue = $creatorRecord;
}
}
$keyLabelPair[$name] = [
'value' => $rowValue,
'fieldLabel' => rtrim($fieldLabel, ':'),
];
}
}
return $propertiesForTable;
return $keyLabelPair;
}
/**
......
......@@ -18,29 +18,25 @@
<div class="card-content">
<div class="row">
<f:if condition="{extraFields.crdate}">
<div class="col-md-6">
<strong>{extraFields.crdate.fieldLabel}</strong><br>
{extraFields.crdate.value}
</div>
</f:if>
<f:if condition="{extraFields.tstamp}">
<div class="col-md-6">
<strong>{extraFields.tstamp.fieldLabel}</strong><br>
{extraFields.tstamp.value}
</div>
</f:if>
<f:for each="{extraFields}" as="extraField">
<f:if condition="{extraField.isDatetime}">
<div class="col-md-6">
<strong>{extraField.fieldLabel}</strong><br>
{extraField.value}
</div>
</f:if>
</f:for>
</div>
<f:if condition="{extraFields.cruser_id.creatorRecord}">
<f:if condition="{extraFields.creatorRecord}">
<div class="row">
<div class="col-md-12">
<div class="media">
<div class="media-left">
{extraFields.cruser_id.creatorRecord.icon -> f:format.raw()}
{extraFields.creatorRecord.value.icon -> f:format.raw()}
</div>
<div class="media-body">
<strong>{extraFields.cruser_id.creatorRecord.username}</strong><br>
{extraFields.cruser_id.creatorRecord.realName}
<strong>{extraFields.creatorRecord.value.username}</strong><br>
{extraFields.creatorRecord.value.realName}
</div>
</div>
</div>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment