Commit 97103f35 authored by Stefan Froemken's avatar Stefan Froemken Committed by Christian Kuhn
Browse files

[BUGFIX] selicon_field does not create thumbnails

A select field with renderType selectSingle can point to a
foreign_table. If on the foreign_table TCA the ctrl keys
selicon_field and selicon_field_path are set, a single foreign row
can have an "icon" field that is shown to represent this row.

The patch fixes a bug where selicon_field of the own table
instead of the foreign table was used.
Additionally, in master the icon path resolving changed
with #74157 leading to broken icon path in this case. This is
fixed along with a similar change in backend layout code.

Resolves: #75577
Related: #74157
Releases: master, 7.6
Change-Id: I50bac28018b17a61a334aac7d241bcdd96663656
Reviewed-on: https://review.typo3.org/47648

Reviewed-by: Wouter Wolters's avatarWouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters's avatarWouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
parent 1450b10f
......@@ -405,6 +405,7 @@ abstract class AbstractItemProvider
* @param string $fieldName Current handle field name
* @param array $items Incoming items
* @return array Modified item array
* @throws \UnexpectedValueException
*/
protected function addItemsFromForeignTable(array $result, $fieldName, array $items)
{
......@@ -419,6 +420,15 @@ abstract class AbstractItemProvider
$database = $this->getDatabaseConnection();
$foreignTable = $result['processedTca']['columns'][$fieldName]['config']['foreign_table'];
if (!is_array($GLOBALS['TCA'][$foreignTable])) {
throw new \UnexpectedValueException(
'Field ' . $fieldName . ' of table ' . $result['tableName'] . ' reference to foreign table '
. $foreignTable . ', but this table is not defined in TCA',
1439569743
);
}
$foreignTableQueryArray = $this->buildForeignTableQuery($result, $fieldName);
$queryResource = $database->exec_SELECT_queryArray($foreignTableQueryArray);
......@@ -444,25 +454,28 @@ abstract class AbstractItemProvider
$labelPrefix = $result['processedTca']['columns'][$fieldName]['config']['foreign_table_prefix'];
$labelPrefix = $languageService->sL($labelPrefix);
}
$iconFieldName = '';
if (!empty($result['processedTca']['ctrl']['selicon_field'])) {
$iconFieldName = $result['processedTca']['ctrl']['selicon_field'];
}
$iconPath = '';
if (!empty($result['processedTca']['ctrl']['selicon_field_path'])) {
$iconPath = $result['processedTca']['ctrl']['selicon_field_path'];
}
$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
while ($foreignRow = $database->sql_fetch_assoc($queryResource)) {
BackendUtility::workspaceOL($foreignTable, $foreignRow);
if (is_array($foreignRow)) {
// Prepare the icon if available:
// If the foreign table sets selicon_field, this field can contain an image
// that represents this specific row.
$iconFieldName = '';
if (!empty($GLOBALS['TCA'][$foreignTable]['ctrl']['selicon_field'])) {
$iconFieldName = $GLOBALS['TCA'][$foreignTable]['ctrl']['selicon_field'];
}
$iconPath = '';
if (!empty($GLOBALS['TCA'][$foreignTable]['ctrl']['selicon_field_path'])) {
$iconPath = $GLOBALS['TCA'][$foreignTable]['ctrl']['selicon_field_path'];
}
if ($iconFieldName && $iconPath && $foreignRow[$iconFieldName]) {
// Prepare the row icon if available
$iParts = GeneralUtility::trimExplode(',', $foreignRow[$iconFieldName], true);
$icon = '../' . $iconPath . '/' . trim($iParts[0]);
$icon = $iconPath . '/' . trim($iParts[0]);
} else {
// Else, determine icon based on record type, or a generic fallback
$icon = $iconFactory->mapRecordTypeToIconIdentifier($foreignTable, $foreignRow);
}
// Add the item
......@@ -881,27 +894,18 @@ abstract class AbstractItemProvider
}
/**
* Build query to fetch foreign records
* Build query to fetch foreign records. Helper method of
* addItemsFromForeignTable(), do not call otherwise.
*
* @param array $result Result array
* @param string $localFieldName Current handle field name
* @return array Query array ready to be executed via Database->exec_SELECT_queryArray()
* @throws \UnexpectedValueException
*/
protected function buildForeignTableQuery(array $result, $localFieldName)
{
$backendUser = $this->getBackendUser();
$foreignTableName = $result['processedTca']['columns'][$localFieldName]['config']['foreign_table'];
if (!is_array($GLOBALS['TCA'][$foreignTableName])) {
throw new \UnexpectedValueException(
'Field ' . $localFieldName . ' of table ' . $result['tableName'] . ' reference to foreign table '
. $foreignTableName . ', but this table is not defined in TCA',
1439569743
);
}
$foreignTableClauseArray = $this->processForeignTableClause($result, $foreignTableName, $localFieldName);
$queryArray = [];
......
......@@ -111,7 +111,7 @@ class DefaultDataProvider implements DataProviderInterface
if (!empty($icon)) {
$path = rtrim($GLOBALS['TCA']['backend_layout']['ctrl']['selicon_field_path'], '/') . '/';
$iconPath = '../' . $path . $icon;
$iconPath = $path . $icon;
}
return $iconPath;
......
......@@ -1718,6 +1718,81 @@ class TcaSelectItemsTest extends UnitTestCase
$this->assertEquals($expected, $this->subject->addData($input));
}
/**
* @test
*/
public function addDataForeignTableResolvesIconFromSelicon()
{
$input = [
'databaseRow' => [
'aField' => '',
],
'tableName' => 'aTable',
'processedTca' => [
'columns' => [
'aField' => [
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'foreign_table' => 'fTable',
'maxitems' => 1,
],
],
]
],
'rootline' => [],
];
// Fake the foreign_table
$GLOBALS['TCA']['fTable'] = [
'ctrl' => [
'label' => 'icon',
'selicon_field' => 'icon',
'selicon_field_path' => 'uploads/media',
],
'columns' =>[
'icon' => [],
],
];
/** @var BackendUserAuthentication|ObjectProphecy $backendUserProphecy */
$backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
$GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
$backendUserProphecy->getPagePermsClause(1)->shouldBeCalled()->willReturn(' 1=1');
/** @var LanguageService|ObjectProphecy $languageServiceProphecy */
$languageServiceProphecy = $this->prophesize(LanguageService::class);
$GLOBALS['LANG'] = $languageServiceProphecy->reveal();
$languageServiceProphecy->sL(Argument::cetera())->willReturnArgument(0);
/** @var DatabaseConnection|ObjectProphecy $databaseProphecy */
$databaseProphecy = $this->prophesize(DatabaseConnection::class);
$GLOBALS['TYPO3_DB'] = $databaseProphecy->reveal();
$databaseProphecy->sql_error()->shouldBeCalled()->willReturn(false);
$databaseProphecy->sql_free_result(Argument::cetera())->willReturn(null);
// Query on foreign table is successful
$databaseProphecy->exec_SELECT_queryArray(Argument::cetera())->willReturn(true);
// Query returns one row, then false on second call
$foreignTableRowResultOne = [
'uid' => 1,
'icon' => 'foo.jpg',
];
$databaseProphecy->sql_fetch_assoc(Argument::cetera())->shouldBeCalled()->willReturn($foreignTableRowResultOne, false);
$expected = $input;
$expected['processedTca']['columns']['aField']['config']['items'] = [
0 => [
0 => 'foo.jpg',
1 => 1,
2 => 'uploads/media/foo.jpg', // combination of selicon_field_path and the row value of field 'icon'
3 => null,
],
];
$expected['databaseRow']['aField'] = [];
$this->assertEquals($expected, $this->subject->addData($input));
}
/**
* @test
*/
......
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