[TYPO3-dev] Exception, "hidden" and sorting_foreign field of sys_file_reference not honored for pages.media?

Christian Reiter cr at cNOSPAMxd.de
Wed Feb 19 00:33:11 CET 2014


Hi list,

In TYPO3 6.1.7 I've seen some undesired behaviour with FAL.

It appears that in some circumstances,

* The "hidden" field of sys_file_refeence is not checked,
   and this kills the frontend  (Exception)

* The "sorting" available for inline references in the BE
   (stored in sys_file_reference.sorting_foreign) is not checked,
   leading to unexpected results when using e.g. listNum=0
   (in Typoscript)

Scenario:
---------

Editors are adding banner images to "pages" records (Tab "Resources") as 
they have done forever.

The references are read by a typoscript cointaing an IMAGE with

  file {
        import.data = levelfield:1, media
        treatIdAsReference = 1
        import.listNum = 0
        }
(exact conf may vary, no matter if slide, etc..)

Now editors sometimes get a new banner. They like the idea that they can 
"hide" the old reference and add the new one to test it. If the new 
banner is disapproved they delete the new one and unhide the old one 
(without having to pick the reference again)

However whenever there is a hidden old reference as well as a visible 
new one, there is ALWAYS an exception thrown
'No fileusage (sys_file_reference) found for given UID'

But when there is a hidden NEW reference and a visible OLD one the 
exception always disappears.

"Old" meaning "Lower UID entry in sys_file_reference table".

Also when there are several banners, results are confusing, instead of 
just showing "the top one" as expected from listNum=0

Now  the Typoscript import.listNum = 0 could be interpreted that if the 
editor sorts the references in the backend so that the hidden one is at 
bottom, and a visible one at top, he does not get the exception. Because 
listNum=0 should return the first (0 in array) one and that is visible.

This does not help however.

Sorting the visible reference to top does *not* influence what is picked 
as the UID from sys_file_reference by listNum=0 (this is shown directly 
in the exception screen. It is always the same uid picked from 
sys_file_reference no matter what the sorting of several references in 
the BE).

I tried to trace fully how this is rendered. (see below for details)
The result was that I found in class

	TYPO3\CMS\Core\Utility\RootlineUtility

function

	enrichWithRelationFields

the line 267

	$rows = $this->databaseConnection->exec_SELECTgetRows(
		'uid', $table, $whereClause);

which for this case has as $whereClause

	uid_foreign = 15 AND fieldname = 'media'
	AND tablenames = 'pages' AND sys_file_reference.deleted=0

No enableFields.
No sorting.
This will by default tend to return the rows ordered as they were created.

So the old, hidden one first (since it is not deleted)

Reordering in the backend changes the sorting_foreign field in 
sys_file_references but that is not checked for at all.

If the query was

	uid_foreign = 15 AND fieldname = 'media'
	AND tablenames = 'pages' AND sys_file_reference.deleted=0
	and sys_file_reference.hidden=0
	order by sys_file_reference.sorting_foreign

it would change two things:

* Hidden references in pages.media wouldn't kill the frontend

* If you have several visible references and use listNum=0,
   it would actually deliver the top one.

I believe this could be considered a bug, for the reason:

* Unexpected behaviour of implicit logic in Typoscript - listnum=0 
should deliver top reference

* Enablefields not honored in what is effectively a core function

* A legal backend operation (hide reference) plus reference.compliant TS 
leads to a total failure of the page - at worst if a hidden reference is 
sorted to the top it should deliver empty image/warning, but really, 
HIDDEN should be skipped in the frontend - isn't that the point?

----

I think part of the solution would be to read more from TCA.

   TYPO3\CMS\Core\Utility
   \ExtensionManagementUtility::getFileFieldTCAConfig

already does seem to set
	'foreign_sortby' => 'sorting_foreign'

by default but that isn't being read in

   TYPO3\CMS\Core\Utility\RootlineUtility::enrichWithRelationFields

in fact there seems to be no provision for sorting or hidden or TYPO3 
enableFields there whatsoever.

In 4.x this worked because media was simply a comma-separated list and 
listnum would work on that - there as also no hidden status, either a 
file was listed in pages.media or it wasn't.

Using sorting_foreign here would at least enable the workaround of 
escaping the exception by sorting the hidden references to the bottom.

If it is necessary that the rootline record contains hidden file 
references then at least 
\TYPO3\CMS\Core\Resource\ResourceFactory::getFileReferenceObject should 
fail gracefully if it can't resolve due to a hidden UID.

   \TYPO3\CMS\Core\Resource\ResourceFactory::getFileReferenceObject

does

... if (is_object($GLOBALS['TSFE'])) {
$fileReferenceData = 
$GLOBALS['TSFE']->sys_page->checkRecord('sys_file_reference', $uid);
}

and

   TYPO3\CMS\Frontend\Page\PageRepository::checkRecord

does

   $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid = ' . 
$uid . $this->enableFields($table));

This means:

enableFields are *ignored* when putting sys_file_reference entries into 
the rootline.

Since sorting is ignored also, any hidden references always win first 
place if they were the first ones created.

However when the reference stored in the rootline is resolved, 
enableFIelds are *not* ignored.

Therefore the exception.

If enableFields were honored while adding to the rootline it would go away.

Greetings to all,

Christian


-----

My attempt to trace:

TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::getImgResource

does


if ($fileArray['import.']) {
$importedFile = trim($this->stdWrap('', $fileArray['import.']));
if (!empty($importedFile)) {
$file = $importedFile;
}

At this point it gets the ID of the hidden sys_file_reference converted 
from the import. conf

This is done in stdWrap

stdWrap_data delivers BOTH the IDs from  sys_file_reference - the hidden 
one first

stdWrap_listNum then returns only the first

stdWrap_data calls getData which does

switch ($type) {
...
case 'levelfield':
$keyP = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $key);
$nkey = $this->getKey($keyP[0], $GLOBALS['TSFE']->tmpl->rootLine);
$retVal = $this->rootLineValue($nkey, $keyP[1], strtolower($keyP[2]) == 
'slide');
break;

So I need to look how it gets int $GLOBALS['TSFE']->tmpl->rootLine

which I find in TYPO3\CMS\Core\Utility\RootlineUtility
function enrichWithRelationFields




More information about the TYPO3-dev mailing list