[TASK] Use LanguageService inside TSFE 99/52799/9
authorBenni Mack <benni@typo3.org>
Thu, 7 Sep 2017 08:06:31 +0000 (10:06 +0200)
committerSusanne Moog <susanne.moog@typo3.org>
Mon, 16 Oct 2017 18:48:54 +0000 (20:48 +0200)
TSFE does the same logic as $GLOBALS['LANG'] (= LanguageService) for
fetching labels and language files, but with a different language key.

However, LanguageService is not a singleton, so it _can_ be used
multiple times at the same request, so why not use the LanguageService
for labels based on config.sys_language, and the $GLOBALS['LANG'] record
based on the current backend user.

So, TSFE only acts as a wrapper for LanguageService instead of having
duplicate code.

A few now useless internal properties are dropped, some other
methods are deprecated:

- TSFE->LL_files_cache
- TSFE->LL_labels_cache

- TSFE->readLLfile()
- TSFE->getLLL()
- TSFE->initLLvars()

Resolves: #81217
Releases: master
Change-Id: Iae85ac2eda4d7f77960de2d66b9069f6017c31d8
Reviewed-on: https://review.typo3.org/52799
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
typo3/sysext/core/Documentation/Changelog/master/Deprecation-81217-TSFE-relatedLanguageMethods.rst [new file with mode: 0644]
typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
typo3/sysext/frontend/Tests/Unit/ContentObject/ContentObjectRendererTest.php
typo3/sysext/frontend/Tests/Unit/Controller/TypoScriptFrontendControllerTest.php
typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-81217-TSFE-relatedLanguageMethods.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-81217-TSFE-relatedLanguageMethods.rst
new file mode 100644 (file)
index 0000000..45e7b62
--- /dev/null
@@ -0,0 +1,42 @@
+.. include:: ../../Includes.txt
+
+===================================================
+Deprecation: #81217 - TSFE-related language methods
+===================================================
+
+See :issue:`81217`
+
+Description
+===========
+
+The main class for generating frontend output (TypoScriptFrontendController) has been streamlined
+to use the same API within LanguageService.
+
+Therefore the following methods within TypoScriptFrontendController have been marked as deprecated:
+* readLLfile()
+* getLLL()
+* initLLvars()
+
+
+Impact
+======
+
+Calling any of the PHP methods above will trigger a deprecation warning.
+
+
+Affected Installations
+======================
+
+Any TYPO3 installation calling custom frontend code with the methods above.
+
+
+Migration
+=========
+
+Use :php:`TypoScriptFrontendController->sL()` for resolving language labels in the language
+of the Frontend rendering engine.
+
+For doing custom special logic, it is recommend to set up a custom instance of `LanguageService`
+which holds all functionality directly.
+
+.. index:: Frontend, PHP-API, FullyScanned
\ No newline at end of file
index 81abba9..e83df3d 100644 (file)
@@ -30,8 +30,7 @@ use TYPO3\CMS\Core\Database\Query\Restriction\EndTimeRestriction;
 use TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction;
 use TYPO3\CMS\Core\Error\Http\PageNotFoundException;
 use TYPO3\CMS\Core\Error\Http\ServiceUnavailableException;
-use TYPO3\CMS\Core\Localization\Locales;
-use TYPO3\CMS\Core\Localization\LocalizationFactory;
+use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Locking\Exception\LockAcquireWouldBlockException;
 use TYPO3\CMS\Core\Locking\LockFactory;
 use TYPO3\CMS\Core\Locking\LockingStrategyInterface;
@@ -700,23 +699,11 @@ class TypoScriptFrontendController implements LoggerAwareInterface
     public $lang = '';
 
     /**
-     * @var array
-     */
-    public $LL_labels_cache = [];
-
-    /**
-     * @var array
-     */
-    public $LL_files_cache = [];
-
-    /**
-     * List of language dependencies for actual language. This is used for local
-     * variants of a language that depend on their "main" language, like Brazilian,
-     * Portuguese or Canadian French.
+     * Internal calculations for labels
      *
-     * @var array
+     * @var LanguageService
      */
-    protected $languageDependencies = [];
+    protected $languageService;
 
     /**
      * @var LockingStrategyInterface[][]
@@ -2554,7 +2541,14 @@ class TypoScriptFrontendController implements LoggerAwareInterface
         }
 
         // Initialize charset settings etc.
-        $this->initLLvars();
+        $languageKey = $this->config['config']['language'] ?? 'default';
+        $this->lang = $languageKey;
+        $this->setOutputLanguage($languageKey);
+
+        // Rendering charset of HTML page.
+        if (isset($this->config['config']['metaCharset']) && $this->config['config']['metaCharset'] !== 'utf-8') {
+            $this->metaCharset = $this->config['config']['metaCharset'];
+        }
 
         // Get values from TypoScript:
         $this->sys_language_uid = ($this->sys_language_content = (int)$this->config['config']['sys_language_uid']);
@@ -2633,7 +2627,7 @@ class TypoScriptFrontendController implements LoggerAwareInterface
             if (!empty($this->config['config']['sys_language_isocode_default'])) {
                 $this->sys_language_isocode = $this->config['config']['sys_language_isocode_default'];
             } else {
-                $this->sys_language_isocode = $this->lang !== 'default' ? $this->lang : 'en';
+                $this->sys_language_isocode = $languageKey !== 'default' ? $languageKey : 'en';
             }
         }
 
@@ -4064,27 +4058,7 @@ class TypoScriptFrontendController implements LoggerAwareInterface
      */
     public function sL($input)
     {
-        if (substr($input, 0, 4) !== 'LLL:') {
-            // Not a label, return the key as this
-            return $input;
-        }
-        // If cached label
-        if (!isset($this->LL_labels_cache[$this->lang][$input])) {
-            $restStr = trim(substr($input, 4));
-            $extPrfx = '';
-            if (strpos($restStr, 'EXT:') === 0) {
-                $restStr = trim(substr($restStr, 4));
-                $extPrfx = 'EXT:';
-            }
-            $parts = explode(':', $restStr);
-            $parts[0] = $extPrfx . $parts[0];
-            // Getting data if not cached
-            if (!isset($this->LL_files_cache[$parts[0]])) {
-                $this->LL_files_cache[$parts[0]] = $this->readLLfile($parts[0]);
-            }
-            $this->LL_labels_cache[$this->lang][$input] = $this->getLLL($parts[1], $this->LL_files_cache[$parts[0]]);
-        }
-        return $this->LL_labels_cache[$this->lang][$input];
+        return $this->languageService->sL($input);
     }
 
     /**
@@ -4092,37 +4066,12 @@ class TypoScriptFrontendController implements LoggerAwareInterface
      *
      * @param string $fileRef Reference to a relative filename to include.
      * @return array Returns the $LOCAL_LANG array found in the file. If no array found, returns empty array.
+     * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
      */
     public function readLLfile($fileRef)
     {
-        /** @var $languageFactory LocalizationFactory */
-        $languageFactory = GeneralUtility::makeInstance(LocalizationFactory::class);
-
-        if ($this->lang !== 'default') {
-            $languages = array_reverse($this->languageDependencies);
-            // At least we need to have English
-            if (empty($languages)) {
-                $languages[] = 'default';
-            }
-        } else {
-            $languages = ['default'];
-        }
-
-        $localLanguage = [];
-        foreach ($languages as $language) {
-            $tempLL = $languageFactory->getParsedData($fileRef, $language);
-            $localLanguage['default'] = $tempLL['default'];
-            if (!isset($localLanguage[$this->lang])) {
-                $localLanguage[$this->lang] = $localLanguage['default'];
-            }
-            if ($this->lang !== 'default' && isset($tempLL[$language])) {
-                // Merge current language labels onto labels from previous language
-                // This way we have a label with fall back applied
-                ArrayUtility::mergeRecursiveWithOverrule($localLanguage[$this->lang], $tempLL[$language], true, false);
-            }
-        }
-
-        return $localLanguage;
+        trigger_error('This method will be removed in TYPO3 v10, as the method LanguageService->includeLLFile() can be used directly.', E_USER_DEPRECATED);
+        return $this->languageService->includeLLFile($fileRef, false, true);
     }
 
     /**
@@ -4131,9 +4080,11 @@ class TypoScriptFrontendController implements LoggerAwareInterface
      * @param string $index Local_lang key for which to return label (language is determined by $this->lang)
      * @param array $LOCAL_LANG The locallang array in which to search
      * @return string Label value of $index key.
+     * @deprecated since TYPO3 v9, will be removed in TYPO3 v10, use LanguageService->getLLL() directly
      */
     public function getLLL($index, $LOCAL_LANG)
     {
+        trigger_error('This method will be removed in TYPO3 v10, as the method LanguageService->getLLL() can be used directly.', E_USER_DEPRECATED);
         if (isset($LOCAL_LANG[$this->lang][$index][0]['target'])) {
             return $LOCAL_LANG[$this->lang][$index][0]['target'];
         }
@@ -4145,28 +4096,15 @@ class TypoScriptFrontendController implements LoggerAwareInterface
 
     /**
      * Initializing the getLL variables needed.
+     *
+     * @see settingLanguage()
+     * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.
      */
     public function initLLvars()
     {
-        // Init languageDependencies list
-        $this->languageDependencies = [];
-        // Setting language key and split index:
+        trigger_error('This method will be removed in TYPO3 v10, the initialization can be altered via hooks within settingLanguage().', E_USER_DEPRECATED);
         $this->lang = $this->config['config']['language'] ?: 'default';
-        $this->pageRenderer->setLanguage($this->lang);
-
-        // Finding the requested language in this list based
-        // on the $lang key being inputted to this function.
-        /** @var $locales Locales */
-        $locales = GeneralUtility::makeInstance(Locales::class);
-        $locales->initialize();
-
-        // Language is found. Configure it:
-        if (in_array($this->lang, $locales->getLocales())) {
-            $this->languageDependencies[] = $this->lang;
-            foreach ($locales->getLocaleDependencies($this->lang) as $language) {
-                $this->languageDependencies[] = $language;
-            }
-        }
+        $this->setOutputLanguage($this->lang);
 
         // Rendering charset of HTML page.
         if ($this->config['config']['metaCharset']) {
@@ -4174,6 +4112,21 @@ class TypoScriptFrontendController implements LoggerAwareInterface
         }
     }
 
+    /**
+     * Sets all internal measures what language the page should be rendered.
+     * This is not for records, but rather the HTML / charset and the locallang labels
+     *
+     * @param string $language - usually set via TypoScript config.language = dk
+     */
+    protected function setOutputLanguage($language = 'default')
+    {
+        $this->pageRenderer->setLanguage($language);
+        $this->languageService = GeneralUtility::makeInstance(LanguageService::class);
+        // Always disable debugging for TSFE
+        $this->languageService->debugKey = false;
+        $this->languageService->init($language);
+    }
+
     /**
      * Converts input string from utf-8 to metaCharset IF the two charsets are different.
      *
index efbc8f0..93a153d 100644 (file)
@@ -129,7 +129,7 @@ class ContentObjectRendererTest extends \TYPO3\TestingFramework\Core\Unit\UnitTe
         $this->frontendControllerMock =
             $this->getAccessibleMock(
                 TypoScriptFrontendController::class,
-            ['dummy'],
+            ['sL'],
                 [],
                 '',
                 false
@@ -1578,10 +1578,7 @@ class ContentObjectRendererTest extends \TYPO3\TestingFramework\Core\Unit\UnitTe
     {
         $key = $this->getUniqueId('someKey');
         $value = $this->getUniqueId('someValue');
-        $language = $this->getUniqueId('someLanguage');
-        $GLOBALS['TSFE']->LL_labels_cache[$language]['LLL:' . $key] = $value;
-        $GLOBALS['TSFE']->lang = $language;
-
+        $GLOBALS['TSFE']->expects($this->once())->method('sL')->with('LLL:' . $key)->will($this->returnValue($value));
         $this->assertEquals($value, $this->subject->getData('lll:' . $key));
     }
 
index 3c006eb..9b93c7d 100644 (file)
@@ -108,6 +108,8 @@ class TypoScriptFrontendControllerTest extends \TYPO3\TestingFramework\Core\Unit
     public function localizationReturnsUnchangedStringIfNotLocallangLabel()
     {
         $string = $this->getUniqueId();
+        $this->subject->page = [];
+        $this->subject->settingLanguage();
         $this->assertEquals($string, $this->subject->sL($string));
     }
 
index 6da30b7..eac2fda 100644 (file)
@@ -1268,4 +1268,25 @@ return [
             'Breaking-82701-AlwaysConsiderPublishingReferencesInWorkspaces.rst',
         ],
     ],
+    'TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->readLLfile' => [
+        'numberOfMandatoryArguments' => 1,
+        'maximumNumberOfArguments' => 1,
+        'restFiles' => [
+            'Deprecation-81217-TSFE-relatedLanguageMethods.rst',
+        ],
+    ],
+    'TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->getLLL' => [
+        'numberOfMandatoryArguments' => 2,
+        'maximumNumberOfArguments' => 2,
+        'restFiles' => [
+            'Deprecation-81217-TSFE-relatedLanguageMethods.rst',
+        ],
+    ],
+    'TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->initLLvars' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Deprecation-81217-TSFE-relatedLanguageMethods.rst',
+        ],
+    ],
 ];