Project

General

Profile

Actions

Bug #103063

open

Extbase repository does not respect fallback chain

Added by Jens Bergau 10 months ago. Updated 5 days ago.

Status:
Under Review
Priority:
Should have
Assignee:
-
Category:
Extbase
Target version:
-
Start date:
2024-02-06
Due date:
% Done:

0%

Estimated time:
TYPO3 Version:
12
PHP Version:
8.2
Tags:
Complexity:
medium
Is Regression:
Sprint Focus:

Description

Topic
In a site with multiple languages and fallback chains configured, extbase models retrieved by an extbase repository do not respect the configured fallback chains.

Example

SiteConfig (only relevant parts):

languages:
  -
    title: 'English (Global)'
    enabled: true
    languageId: 0
    base: /en/
  -
    title: ES-ES
    enabled: true
    base: /es-es/
    typo3Language: es
    fallbackType: strict
    flag: es
    languageId: 15
  -
    title: 'AR-ES'
    enabled: true
    base: /es-ar/
    typo3Language: es
    fallbackType: fallback
    fallbacks: 15
    languageId: 5

Extbase Models in DB:

uid, sys_language_uid, title, l10n_parent
1, 0, 'Model 1 global', 0
2, 15, 'Model 1 spanish', 1
3, 0, 'Model 2 global', 0
4, 5, 'Model 2 spanish argentina', 3
5, 15, 'Model 2 spanish', 3

Using a extbase repository $repository->findAll() return the following results:

1, 0, 'Model 1 global', 0
4, 5, 'Model 2 spanish argentina', 3

instead of the expected result:

2, 15, 'Model 1 spanish', 1
4, 5, 'Model 2 spanish argentina', 3

I've tracked the problem down to
\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbBackend->overlayLanguageAndWorkspaceForSingleRecord

in line 540 a new instance of LanguageAspect is created but without handing over the fallbackChain of the original languageAspect:

$customLanguageAspect = new LanguageAspect($languageUid, $languageUid, LanguageAspect::OVERLAYS_MIXED);
$row = $pageRepository->getLanguageOverlay($tableName, $row, $customLanguageAspect);

I am not sure, if this is done with purpose, but the pageRepository further more does not know about the configured fallbackChain and so cannot return the correct record. In my opinion the above code should look like this:

$customLanguageAspect = new LanguageAspect($languageUid, $languageUid, LanguageAspect::OVERLAYS_MIXED, $languageAspect->getFallbackChain());
$row = $pageRepository->getLanguageOverlay($tableName, $row, $customLanguageAspect);

Actions #1

Updated by Jens Bergau 10 months ago

Topic
In a site with multiple languages and fallback chains configured, extbase models retrieved by an extbase repository do not respect the configured fallback chains.

Example

SiteConfig (only relevant parts):

languages:
  -
    title: 'English (Global)'
    enabled: true
    languageId: 0
    base: /en/
  -
    title: ES-ES
    enabled: true
    base: /es-es/
    typo3Language: es
    fallbackType: strict
    flag: es
    languageId: 15
  -
    title: 'AR-ES'
    enabled: true
    base: /es-ar/
    typo3Language: es
    fallbackType: fallback
    fallbacks: 15
    languageId: 5

Extbase Models in DB:

uid, sys_language_uid, title, l10n_parent
1, 0, 'Model 1 global', 0
2, 15, 'Model 1 spanish', 1
3, 0, 'Model 2 global', 0
4, 5, 'Model 2 spanish argentina', 3
5, 15, 'Model 2 spanish', 3

Using an extbase repository $repository->findAll() returns the following results in language=5:

1, 0, 'Model 1 global', 0
4, 5, 'Model 2 spanish argentina', 3

instead of the expected result:

2, 15, 'Model 1 spanish', 1
4, 5, 'Model 2 spanish argentina', 3

I've tracked the problem down to
\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbBackend->overlayLanguageAndWorkspaceForSingleRecord

in line 540 a new instance of LanguageAspect is created but without handing over the fallbackChain of the original languageAspect:

$customLanguageAspect = new LanguageAspect($languageUid, $languageUid, LanguageAspect::OVERLAYS_MIXED);
$row = $pageRepository->getLanguageOverlay($tableName, $row, $customLanguageAspect);

I am not sure, if this is done with purpose, but the pageRepository further more does not know about the configured fallbackChain and so cannot return the correct record. In my opinion the above code should look like this:

$customLanguageAspect = new LanguageAspect($languageUid, $languageUid, LanguageAspect::OVERLAYS_MIXED, $languageAspect->getFallbackChain());
$row = $pageRepository->getLanguageOverlay($tableName, $row, $customLanguageAspect);
Actions #2

Updated by Pascal Geldmacher 4 months ago

I have the same problem.

I found out that the function in Backend.php is the problem.


    /**
     * Returns the object with the (internal) identifier, if it is known to the
     * backend. Otherwise NULL is returned.
     *
     * @param string $identifier
     * @param string $className
     * @return object|null The object for the identifier if it is known, or NULL
     */
    public function getObjectByIdentifier($identifier, $className)
    {
        if ($this->session->hasIdentifier($identifier, $className)) {
            return $this->session->getObjectByIdentifier($identifier, $className);
        }
        $query = $this->persistenceManager->createQueryForType($className);
        $query->getQuerySettings()->setRespectStoragePage(false);
        $query->getQuerySettings()->setRespectSysLanguage(false);
        // This allows to fetch IDs for languages for default language AND language IDs
        // This is especially important when using the PropertyMapper of the Extbase MVC part to get
        // an object of the translated version of the incoming ID of a record.
        $languageAspect = $query->getQuerySettings()->getLanguageAspect();
        $languageAspect = new LanguageAspect(
            $languageAspect->getId(),
            $languageAspect->getContentId(),
            $languageAspect->getOverlayType() === LanguageAspect::OVERLAYS_OFF ? LanguageAspect::OVERLAYS_ON_WITH_FLOATING : $languageAspect->getOverlayType()
        );
        $query->getQuerySettings()->setLanguageAspect($languageAspect);
        return $query->matching($query->equals('uid', $identifier))->execute()->getFirst();
    }

The code get the languageAspect from the QuerySettings with the correct fallbackchain and then, I dont' know why but ok, created a new LanguageAspect object but without the fallbackchain, as fourth parameter.

I think that this would be the correct implementation, wouldn't it?

 $languageAspect = $query->getQuerySettings()->getLanguageAspect();
        $languageAspect = new LanguageAspect(
            $languageAspect->getId(),
            $languageAspect->getContentId(),
            $languageAspect->getOverlayType() === LanguageAspect::OVERLAYS_OFF ? LanguageAspect::OVERLAYS_ON_WITH_FLOATING : $languageAspect->getOverlayType(),
            $languageAspect->getFallbackChain()
        );
Actions #3

Updated by Gerrit Code Review 7 days ago

  • Status changed from New to Under Review

Patch set 1 for branch main of project Packages/TYPO3.CMS has been pushed to the review server.
It is available at https://review.typo3.org/c/Packages/TYPO3.CMS/+/87036

Actions #4

Updated by Gerrit Code Review 5 days ago

Patch set 2 for branch main of project Packages/TYPO3.CMS has been pushed to the review server.
It is available at https://review.typo3.org/c/Packages/TYPO3.CMS/+/87036

Actions

Also available in: Atom PDF