[BUGFIX] Bring back findByUid behavior for L>0 35/58635/12
authorTymoteusz Motylewski <t.motylewski@gmail.com>
Mon, 15 Oct 2018 10:20:48 +0000 (12:20 +0200)
committerGeorg Ringer <georg.ringer@gmail.com>
Sat, 20 Oct 2018 08:45:02 +0000 (10:45 +0200)
findByUid as well as getObjectByIdentifier will always overlay records
to a language from the global context.

This solves the problem with controller arguments not being translated,
when default language record was used in the URL.

Resolves: #86619
Releases: master
Related: #82363
Change-Id: I823cdc1118a8217e306473b1596d349cc7ca08d4
Reviewed-on: https://review.typo3.org/58635
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein <markus.klein@typo3.org>
Reviewed-by: Alexander Grein <alexander.grein@gmail.com>
Tested-by: Alexander Grein <alexander.grein@gmail.com>
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: Georg Ringer <georg.ringer@gmail.com>
typo3/sysext/core/Documentation/Changelog/9.5/Important-82363-MakeExtBaseTranslationHandlingConsistentWithTyposcript.rst
typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php
typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbBackend.php
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Controller/BlogController.php
typo3/sysext/extbase/Tests/Functional/Mvc/Controller/ControllerArgumentsMappingTest.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Persistence/QueryLocalizedDataTest.php

index 183e31e..573fc65 100644 (file)
@@ -153,9 +153,9 @@ the `uid` of the translated record is kept in the `_localizedUid`.
 
 See tests in :file:`extbase/Tests/Functional/Persistence/QueryLocalizedDataTest.php`.
 
-The :php:`$repository->findByUid()` method takes current rendering language into account (e.g. L=1). It does not take
-`defaultQuerySetting` set on the repository into account.
-The result of this method also depends on whether `languageOverlayMode` is set or not.
+The :php:`$repository->findByUid()` (or :php:`$persistenceManager->getObjectByIdentifier()`) method takes current
+rendering language into account (e.g. L=1). It does not take `defaultQuerySetting` set on the repository into account.
+This method always performs an overlay.
 Values in braces show previous behaviour (disabled flag) if different than current.
 
 The bottom line is that with the feature flag on, you can now use  :php:`findByUid()` using translated record uid to get
@@ -166,24 +166,25 @@ translated content independently from language set in global context.
 +-------------------+----------------+----------------------+----------------------+----------------------+----------------------+
 | repository method | property       | Overlay              | No overlay           | Overlay              | No overlay           |
 +===================+================+======================+======================+======================+======================+
-| findByUid(2)      | title          | Post 2               | Post 2               | Post 2 (Post 2 - DK) | Post 2 (Post 2 - DK) |
+| findByUid(2)      | title          | Post 2               | Post 2               | Post 2 - DK          | Post 2 - DK          |
 +-------------------+----------------+----------------------+----------------------+----------------------+----------------------+
 |                   | uid            | 2                    | 2                    | 2                    | 2                    |
 +-------------------+----------------+----------------------+----------------------+----------------------+----------------------+
-|                   | _localizedUid  | 2                    | 2                    | 2 (11)               | 2 (11)               |
+|                   | _localizedUid  | 2                    | 2                    | 11                   | 11                   |
 +-------------------+----------------+----------------------+----------------------+----------------------+----------------------+
 | findByUid(11)     | title          | Post 2 - DK (Post 2) | Post 2 - DK (Post 2) | Post 2 - DK          | Post 2 - DK          |
 +-------------------+----------------+----------------------+----------------------+----------------------+----------------------+
-|                   | uid            | 2 (2)                | 11 (2)               | 2                    | 11 (2)               |
+|                   | uid            | 2                    | 2                    | 2                    | 2                    |
 +-------------------+----------------+----------------------+----------------------+----------------------+----------------------+
 |                   | _localizedUid  | 11 (2)               | 11 (2)               | 11                   | 11                   |
 +-------------------+----------------+----------------------+----------------------+----------------------+----------------------+
 
 .. note::
 
-   Note that :php:`$repository->findByUid()` behaves differently than a custom query by an `uid`
-   like :php:`$query->matching($query->equals('uid', 11));` The custom query will return `null` if passed `uid` doesn't match
-   language set in the :php:`$querySettings->setLanguageUid()` method.
+   Note that :php:`$repository->findByUid()` internally sets :php:`respectSysLanguage(false)` so it behaves differently
+   than a regular query by an `uid` like :php:`$query->matching($query->equals('uid', 11));`
+   The regular query will return :php:`null` if passed `uid` doesn't match
+   the language set in the :php:`$querySettings->setLanguageUid()` method.
 
 Filtering & sorting
 -------------------
index b15bd9b..8a90169 100644 (file)
@@ -280,6 +280,7 @@ class Backend implements \TYPO3\CMS\Extbase\Persistence\Generic\BackendInterface
         $query = $this->persistenceManager->createQueryForType($className);
         $query->getQuerySettings()->setRespectStoragePage(false);
         $query->getQuerySettings()->setRespectSysLanguage(false);
+        $query->getQuerySettings()->setLanguageOverlayMode(true);
         return $query->matching($query->equals('uid', $identifier))->execute()->getFirst();
     }
 
index 06eb258..ab50545 100644 (file)
@@ -709,13 +709,18 @@ class Typo3DbBackend implements BackendInterface, SingletonInterface
                 } else {
                     $languageUid = (int)$querySettings->getLanguageUid();
                     if (!$querySettings->getRespectSysLanguage()
-                        && isset($row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']]) > 0
-                        && (!$query instanceof Query || !$query->getParentQuery())) {
-                        //we're mapping the aggregate root.
+                        && isset($row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']])
+                        && $row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']] > 0
+                        && (!$query instanceof Query || !$query->getParentQuery())
+                    ) {
+                        //no parent query means we're processing the aggregate root.
+                        //respectSysLanguage is false which means that records returned by the query
+                        //might be from different languages (which is desired).
+                        //So we need to force language used for overlay to the language of the current record.
                         $languageUid = $row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']];
                     }
                     if (isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']) && $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] > 0) {
-                        //force overlay
+                        //force overlay by faking default language record, as getRecordOverlay can only handle default language records
                         $row['uid'] = $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']];
                         $row[$GLOBALS['TCA'][$tableName]['ctrl']['languageField']] = 0;
                     }
index 8c2b3d3..e98c518 100644 (file)
@@ -15,6 +15,7 @@ namespace ExtbaseTeam\BlogExample\Controller;
  * The TYPO3 project - inspiring people to share!
  */
 
+use ExtbaseTeam\BlogExample\Domain\Model\Blog;
 use TYPO3\CMS\Extbase\Annotation as Extbase;
 use TYPO3\CMS\Extbase\Annotation\IgnoreValidation;
 
@@ -40,9 +41,6 @@ class BlogController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
      */
     protected $dataMapFactory;
 
-    /**
-     * @return array
-     */
     public function listAction()
     {
         $blogs = $this->blogRepository->findAll();
@@ -51,6 +49,11 @@ class BlogController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
         $this->view->assign('value', $value);
     }
 
+    public function detailsAction(Blog $blog=null)
+    {
+        return $blog ? $blog->getTitle() : '';
+    }
+
     /**
      * @return string
      */
diff --git a/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/ControllerArgumentsMappingTest.php b/typo3/sysext/extbase/Tests/Functional/Mvc/Controller/ControllerArgumentsMappingTest.php
new file mode 100644 (file)
index 0000000..0ef0098
--- /dev/null
@@ -0,0 +1,120 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Extbase\Tests\Functional\Mvc\Controller;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use ExtbaseTeam\BlogExample\Controller\BlogController;
+use TYPO3\CMS\Core\Context\Context;
+use TYPO3\CMS\Core\Context\LanguageAspect;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Mvc\Web\Request;
+use TYPO3\CMS\Extbase\Mvc\Web\Response;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+
+/**
+ * Test case
+ */
+class ControllerArgumentsMappingTest extends \TYPO3\TestingFramework\Core\Functional\FunctionalTestCase
+{
+    /**
+     * @var \TYPO3\CMS\Extbase\Mvc\Web\Request
+     */
+    protected $request;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Mvc\Web\Response
+     */
+    protected $response;
+
+    /**
+     * @var BlogController
+     */
+    protected $controller;
+
+    /**
+     * @var array
+     */
+    protected $testExtensionsToLoad = ['typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example'];
+
+    /**
+     * @var array
+     */
+    protected $coreExtensionsToLoad = ['extbase', 'fluid'];
+
+    protected function setUp()
+    {
+        parent::setUp();
+
+        $this->importCSVDataSet(ORIGINAL_ROOT . 'typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/translatedBlogExampleData.csv');
+
+        $objectManager = GeneralUtility::makeInstance(ObjectManager::class);
+        $configuration = [
+            'features' => ['consistentTranslationOverlayHandling' => 1],
+            'persistence' => [
+                'storagePid' => 20,
+                'classes' => [
+                    'TYPO3\CMS\Extbase\Domain\Model\Category' => [
+                        'mapping' => ['tableName' => 'sys_category']
+                    ]
+                ]
+            ]
+        ];
+        $configurationManager = $objectManager->get(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::class);
+        $configurationManager->setConfiguration($configuration);
+        $this->request = $objectManager->get(Request::class);
+        $this->request->setControllerVendorName('ExtbaseTeam\\BlogExample');
+        $this->request->setPluginName('Pi1');
+        $this->request->setControllerExtensionName(BlogController::class);
+        $this->request->setControllerName('Blog');
+        $this->request->setMethod('GET');
+        $this->request->setFormat('html');
+
+        $this->response = $objectManager->get(Response::class);
+
+        $this->controller = $objectManager->get(BlogController::class);
+    }
+
+    public function actionGetsBlogFromUidArgumentDataProvider()
+    {
+        return [
+            [
+                'language' => 0,
+                'blogUid' => 1,
+                'blogTitle' => 'Blog 1',
+            ],
+            [
+                'language' => 1,
+                'blogUid' => 1,
+                'blogTitle' => 'Blog 1 DK',
+            ],
+        ];
+    }
+
+    /**
+     * @test
+     * @dataProvider actionGetsBlogFromUidArgumentDataProvider
+     */
+    public function actionGetsBlogFromUidArgument(int $language, int $blogUid, string $expectedTitle)
+    {
+        $context = GeneralUtility::makeInstance(Context::class);
+        $context->setAspect('language', new LanguageAspect($language, $language, LanguageAspect::OVERLAYS_ON));
+        $this->request->setControllerActionName('details');
+        $this->request->setArgument('blog', $blogUid);
+
+        $this->controller->processRequest($this->request, $this->response);
+
+        $this->assertEquals($expectedTitle, $this->response->getContent());
+    }
+}
index ce37acf..d5115de 100644 (file)
@@ -178,7 +178,7 @@ class QueryLocalizedDataTest extends \TYPO3\TestingFramework\Core\Functional\Fun
         $this->persistenceManager->clearState();
 
         $post2translated = $this->postRepository->findByUid(11);
-        $this->assertEquals(['Post 2 - DK', 11, 11, 'Blog 1 DK', 1, 2, 'Translated John', 1, 2], [
+        $this->assertEquals(['Post 2 - DK', 2, 11, 'Blog 1 DK', 1, 2, 'Translated John', 1, 2], [
             $post2translated->getTitle(),
             $post2translated->getUid(),
             $post2translated->_getProperty('_localizedUid'),
@@ -202,7 +202,7 @@ class QueryLocalizedDataTest extends \TYPO3\TestingFramework\Core\Functional\Fun
         $context->setAspect('language', new LanguageAspect(1, 1, LanguageAspect::OVERLAYS_ON));
 
         $post2 = $this->postRepository->findByUid(2);
-        $this->assertEquals(['Post 2', 2, 2, 'Blog 1', 1, 1, 'John', 1, 1], [
+        $this->assertEquals(['Post 2 - DK', 2, 11, 'Blog 1 DK', 1, 2, 'Translated John', 1, 2], [
             $post2->getTitle(),
             $post2->getUid(),
             $post2->_getProperty('_localizedUid'),
@@ -241,7 +241,7 @@ class QueryLocalizedDataTest extends \TYPO3\TestingFramework\Core\Functional\Fun
         $context->setAspect('language', new LanguageAspect(1, 1, LanguageAspect::OVERLAYS_OFF));
 
         $post2 = $this->postRepository->findByUid(2);
-        $this->assertEquals(['Post 2', 2, 2, 'Blog 1', 1, 1, 'John', 1, 1], [
+        $this->assertEquals(['Post 2 - DK', 2, 11, 'Blog 1 DK', 1, 2, 'Translated John', 1, 2], [
             $post2->getTitle(),
             $post2->getUid(),
             $post2->_getProperty('_localizedUid'),
@@ -257,7 +257,7 @@ class QueryLocalizedDataTest extends \TYPO3\TestingFramework\Core\Functional\Fun
         $this->persistenceManager->clearState();
 
         $post2translated = $this->postRepository->findByUid(11);
-        $this->assertEquals(['Post 2 - DK', 11, 11, 'Blog 1 DK', 1, 2, 'Translated John', 1, 2], [
+        $this->assertEquals(['Post 2 - DK', 2, 11, 'Blog 1 DK', 1, 2, 'Translated John', 1, 2], [
             $post2translated->getTitle(),
             $post2translated->getUid(),
             $post2translated->_getProperty('_localizedUid'),
@@ -1107,13 +1107,35 @@ class QueryLocalizedDataTest extends \TYPO3\TestingFramework\Core\Functional\Fun
                  'language' => 1,
                  'overlay' => LanguageAspect::OVERLAYS_ON,
                  'mode' => null,
-                 'expected' => $lang0Expected
+                 'expected' => [
+                     [
+                         'title' => 'Blog 1 DK',
+                         'uid' => 1,
+                         '_localizedUid' => 2,
+                     ],
+                     [
+                         'title' => 'Blog 1 DK',
+                         'uid' => 1,
+                         '_localizedUid' => 2,
+                     ],
+                 ]
              ],
              [
                  'language' => 1,
                  'overlay' => LanguageAspect::OVERLAYS_ON,
                  'mode' => 'strict',
-                 'expected' => $lang0Expected
+                 'expected' => [
+                     [
+                         'title' => 'Blog 1 DK',
+                         'uid' => 1,
+                         '_localizedUid' => 2,
+                     ],
+                     [
+                         'title' => 'Blog 1 DK',
+                         'uid' => 1,
+                         '_localizedUid' => 2,
+                     ],
+                 ]
              ],
              [
                  'language' => 1,