Commit 98a059e8 authored by Andreas Fernandez's avatar Andreas Fernandez Committed by Benni Mack
Browse files

[TASK] Add tests for wrong translation behavior of Extbase

Scenario:

* a site with another language being configured as "strict"
* an Extbase plugin consuming a list of records identified by their
  respective uid
* plugin and records are localized to the site's language

Expectation:

The plugin receives the UIDs of the original record UIDs having
sys_language_uid = 0. The plugin uses a custom Extbase Repository and
passes the UIDs as array to a ->in() clause:

```
$query = $this->createQuery();
$query->matching($query->in('uid', [1, 2, 3]));
```

According to the site configuration, Extbase should be able to find these
records in the default language and either overlay if translated, or
discard them if no translations are available.

Actual result:

Extbase is not able to find any record and thus returns an empty result
set. The identified cause is that Extbase searches the database for the
given record UIDs in conjunction with the current language id,
returning an empty set by definition.

To prove the wrong behavior, tests are added that show the broken
behavior, the actual fix will come with another patch in #88137.

Resolves: #94694
Related: #88137
Releases: master, 10.4
Change-Id: I9a7a6ec5d1b5cfb82e1fc05365fde6e45df12dfc
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/70192

Tested-by: Anja Leichsenring's avatarAnja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: core-ci's avatarcore-ci <typo3@b13.com>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Reviewed-by: Anja Leichsenring's avatarAnja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
parent 5fad4f42
...@@ -82,4 +82,24 @@ ...@@ -82,4 +82,24 @@
<sys_language_uid>2</sys_language_uid> <sys_language_uid>2</sys_language_uid>
<l18n_diffsource></l18n_diffsource> <l18n_diffsource></l18n_diffsource>
</tx_blogexample_domain_model_post> </tx_blogexample_domain_model_post>
<tx_blogexample_domain_model_post>
<uid>12</uid>
<pid>1</pid>
<blog>1</blog>
<content>Lorem ipsum</content>
<title>Post11</title>
<deleted>0</deleted>
<l18n_diffsource></l18n_diffsource>
</tx_blogexample_domain_model_post>
<tx_blogexample_domain_model_post>
<uid>13</uid>
<pid>1</pid>
<l18n_parent>12</l18n_parent>
<l18n_diffsource></l18n_diffsource>
<sys_language_uid>2</sys_language_uid>
<blog>1</blog>
<content>Lorem ipsum</content>
<title>GR:Post11</title>
<deleted>0</deleted>
</tx_blogexample_domain_model_post>
</dataset> </dataset>
...@@ -168,14 +168,14 @@ class TranslatedSiteContentTest extends AbstractDataHandlerActionTestCase ...@@ -168,14 +168,14 @@ class TranslatedSiteContentTest extends AbstractDataHandlerActionTestCase
} }
/** /**
* Dutch language has pages record and some content elements are translated * Danish language has pages record and some content elements are translated
* *
* @return array * @return array
*/ */
public function dutchDataProvider(): array public function danishDataProvider(): array
{ {
// Expected behaviour: // Expected behaviour:
// Page is translated to Dutch, so changing sys_language_mode does NOT change the results // Page is translated to Danish, so changing sys_language_mode does NOT change the results
// Page title is always [DK]Page, and both sys_language_content and sys_language_uid are always 1 // Page title is always [DK]Page, and both sys_language_content and sys_language_uid are always 1
return [ return [
[ [
...@@ -237,12 +237,12 @@ class TranslatedSiteContentTest extends AbstractDataHandlerActionTestCase ...@@ -237,12 +237,12 @@ class TranslatedSiteContentTest extends AbstractDataHandlerActionTestCase
/** /**
* @test * @test
* @dataProvider dutchDataProvider * @dataProvider danishDataProvider
* *
* @param string $fallbackType * @param string $fallbackType
* @param array $visibleRecords * @param array $visibleRecords
*/ */
public function renderingOfDutchLanguage(string $fallbackType, array $visibleRecords): void public function renderingOfDanishLanguage(string $fallbackType, array $visibleRecords): void
{ {
$this->writeSiteConfiguration( $this->writeSiteConfiguration(
'test', 'test',
...@@ -371,7 +371,7 @@ class TranslatedSiteContentTest extends AbstractDataHandlerActionTestCase ...@@ -371,7 +371,7 @@ class TranslatedSiteContentTest extends AbstractDataHandlerActionTestCase
], ],
], ],
], ],
// Dutch elements are shown because of the fallback chain 1,0 - first Dutch, then default language // danish elements are shown because of the fallback chain 1,0 - first danish, then default language
// note that '[DK] Without default language' is NOT shown - due to overlays (fetch default language and overlay it with translations) // note that '[DK] Without default language' is NOT shown - due to overlays (fetch default language and overlay it with translations)
[ [
'fallbackType' => 'fallback', 'fallbackType' => 'fallback',
......
...@@ -106,7 +106,7 @@ class TranslationTest extends FunctionalTestCase ...@@ -106,7 +106,7 @@ class TranslationTest extends FunctionalTestCase
self::assertFalse($querySettings->getLanguageOverlayMode()); self::assertFalse($querySettings->getLanguageOverlayMode());
$postCount = $query->execute()->count(); $postCount = $query->execute()->count();
self::assertSame(3, $postCount); self::assertSame(4, $postCount);
} }
/** /**
...@@ -165,7 +165,7 @@ class TranslationTest extends FunctionalTestCase ...@@ -165,7 +165,7 @@ class TranslationTest extends FunctionalTestCase
$postCount = $query->execute()->count(); $postCount = $query->execute()->count();
self::assertSame(1, $postCount); self::assertSame(2, $postCount);
} }
/** /**
...@@ -191,6 +191,26 @@ class TranslationTest extends FunctionalTestCase ...@@ -191,6 +191,26 @@ class TranslationTest extends FunctionalTestCase
self::assertSame('B EN:Post1', $posts[1]->getTitle()); self::assertSame('B EN:Post1', $posts[1]->getTitle());
} }
/**
* @test
*/
public function fetchingPostsByInClauseReturnsDefaultPostsWithFallback(): void
{
$query = $this->postRepository->createQuery();
$querySettings = $query->getQuerySettings();
$querySettings->setStoragePageIds([1]);
$querySettings->setRespectSysLanguage(false);
$querySettings->setLanguageOverlayMode(true);
$querySettings->setLanguageUid(2);
$query->matching($query->in('uid', [4]));
/** @var Post[]|array $posts */
$posts = $query->execute()->toArray();
self::assertCount(1, $posts);
self::assertSame('Post2', $posts[0]->getTitle());
}
/** /**
* This tests shows overlays in action * This tests shows overlays in action
* *
...@@ -211,8 +231,9 @@ class TranslationTest extends FunctionalTestCase ...@@ -211,8 +231,9 @@ class TranslationTest extends FunctionalTestCase
/** @var Post[]|array $posts */ /** @var Post[]|array $posts */
$posts = $query->execute()->toArray(); $posts = $query->execute()->toArray();
self::assertCount(1, $posts); self::assertCount(2, $posts);
self::assertSame('GR:Post1', $posts[0]->getTitle()); self::assertSame('GR:Post1', $posts[0]->getTitle());
self::assertSame('GR:Post11', $posts[1]->getTitle());
} }
/** /**
...@@ -235,8 +256,79 @@ class TranslationTest extends FunctionalTestCase ...@@ -235,8 +256,79 @@ class TranslationTest extends FunctionalTestCase
/** @var Post[]|array $posts */ /** @var Post[]|array $posts */
$posts = $query->execute()->toArray(); $posts = $query->execute()->toArray();
self::assertCount(1, $posts); self::assertCount(2, $posts);
self::assertSame('GR:Post1', $posts[0]->getTitle()); self::assertSame('GR:Post1', $posts[0]->getTitle());
self::assertSame('GR:Post11', $posts[1]->getTitle());
}
public function fetchingTranslatedPostByUidDataProvider(): array
{
return [
'with one id' => [
'input' => [12],
'expectedTitles' => ['GR:Post11'],
],
'with two ids' => [
'input' => [12, 1],
'expectedTitles' => ['GR:Post11', 'GR:Post1'],
],
];
}
/**
* @dataProvider fetchingTranslatedPostByUidDataProvider
* @test
*/
public function fetchingTranslatedPostByInClauseWithStrictLanguageSettings(array $input, array $expectedTitles): void
{
$query = $this->postRepository->createQuery();
$querySettings = $query->getQuerySettings();
$querySettings->setStoragePageIds([1]);
$querySettings->setRespectSysLanguage(true);
$querySettings->setLanguageUid(2);
$querySettings->setLanguageOverlayMode('hideNonTranslated');
$query->matching($query->in('uid', $input));
/** @var Post[]|array $posts */
$posts = $query->execute()->toArray();
// @todo: wrong assertion
// We're simulating a strict language configuration where a blog post (uid=12 or uid=1) has been translated to another
// language. However, Extbase is not able to find the translated record via ->in() and therefore returns an
// empty result set. This will be fixed with https://review.typo3.org/c/Packages/TYPO3.CMS/+/67893
self::assertCount(0, $posts);
// self::assertCount(count($expectedTitles), $posts);
// self::assertEqualsCanonicalizing($expectedTitles, array_map(static function(Post $post) { return $post->getTitle(); }, $posts));
}
/**
* @dataProvider fetchingTranslatedPostByUidDataProvider
* @test
*/
public function fetchingTranslatedPostByEqualsUidClauseWithStrictLanguageSettings(array $input, array $expectedTitles): void
{
$query = $this->postRepository->createQuery();
$querySettings = $query->getQuerySettings();
$querySettings->setStoragePageIds([1]);
$querySettings->setRespectSysLanguage(true);
$querySettings->setLanguageUid(2);
$querySettings->setLanguageOverlayMode('hideNonTranslated');
$constraints = [];
foreach ($input as $uid) {
$constraints[] = $query->equals('uid', $uid);
}
$query->matching($query->logicalOr(...$constraints));
/** @var Post[]|array $posts */
$posts = $query->execute()->toArray();
// @todo: wrong assertion
// We're simulating a strict language configuration where a blog post (uid=12 or uid=1) has been translated to another
// language. However, Extbase is not able to find the translated record via ->equals(uid=12 OR uid=1 OR ...) and therefore returns an
// empty result set. This will be fixed with https://review.typo3.org/c/Packages/TYPO3.CMS/+/67893
self::assertCount(0, $posts);
// self::assertCount(count($expectedTitles), $posts);
// self::assertEqualsCanonicalizing($expectedTitles, array_map(static function(Post $post) { return $post->getTitle(); }, $posts));
} }
/** /**
...@@ -313,7 +405,7 @@ class TranslationTest extends FunctionalTestCase ...@@ -313,7 +405,7 @@ class TranslationTest extends FunctionalTestCase
/** @var Post[] $posts */ /** @var Post[] $posts */
$posts = $query->execute()->toArray(); $posts = $query->execute()->toArray();
self::assertCount(4, $posts); self::assertCount(5, $posts);
self::assertSame('Post10', $posts[3]->getTitle()); self::assertSame('Post10', $posts[3]->getTitle());
} }
...@@ -339,10 +431,11 @@ class TranslationTest extends FunctionalTestCase ...@@ -339,10 +431,11 @@ class TranslationTest extends FunctionalTestCase
/** @var Post[] $posts */ /** @var Post[] $posts */
$posts = $query->execute()->toArray(); $posts = $query->execute()->toArray();
self::assertCount(2, $posts); self::assertCount(3, $posts);
self::assertSame('GR:Post1', $posts[0]->getTitle()); self::assertSame('GR:Post1', $posts[0]->getTitle());
self::assertSame('GR:Post10', $posts[1]->getTitle()); self::assertSame('GR:Post10', $posts[1]->getTitle());
self::assertSame('GR:Post11', $posts[2]->getTitle());
} }
/** /**
...@@ -370,13 +463,14 @@ class TranslationTest extends FunctionalTestCase ...@@ -370,13 +463,14 @@ class TranslationTest extends FunctionalTestCase
/** @var Post[] $posts */ /** @var Post[] $posts */
$posts = $query->execute()->toArray(); $posts = $query->execute()->toArray();
self::assertCount(4, $posts); self::assertCount(5, $posts);
self::assertSame('GR:Post1', $posts[0]->getTitle()); self::assertSame('GR:Post1', $posts[0]->getTitle());
self::assertSame('Post2', $posts[1]->getTitle()); self::assertSame('Post2', $posts[1]->getTitle());
self::assertSame('Post3', $posts[2]->getTitle()); self::assertSame('Post3', $posts[2]->getTitle());
// once the issue is fixed this assertion should be GR:Post10 // once the issue is fixed this assertions should be GR:Post10
self::assertSame('Post10', $posts[3]->getTitle()); self::assertSame('Post10', $posts[3]->getTitle());
self::assertSame('GR:Post11', $posts[4]->getTitle());
} }
/** /**
...@@ -420,8 +514,9 @@ class TranslationTest extends FunctionalTestCase ...@@ -420,8 +514,9 @@ class TranslationTest extends FunctionalTestCase
$query->matching($query->equals('blog.title', 'Blog1')); $query->matching($query->equals('blog.title', 'Blog1'));
/** @var Post[]|array $posts */ /** @var Post[]|array $posts */
$posts = $query->execute()->toArray(); $posts = $query->execute()->toArray();
self::assertCount(1, $posts); self::assertCount(2, $posts);
self::assertSame('GR:Post1', $posts[0]->getTitle()); self::assertSame('GR:Post1', $posts[0]->getTitle());
self::assertSame('GR:Post11', $posts[1]->getTitle());
} }
/** /**
......
Markdown is supported
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