[BUGFIX] Typo3DbBackend language handling crashes in BE
authorNicole Cordes <n.cordes@biz-design.biz>
Fri, 19 Oct 2012 22:01:59 +0000 (00:01 +0200)
committerHelmut Hummel <helmut.hummel@typo3.org>
Sun, 4 Nov 2012 13:00:11 +0000 (14:00 +0100)
Within a past commit the language handling was completly rewritten to
support language uids other than 0. This was done for frontend only so we
have to add a backend handling as well.

The language uid is now taken from the L parameter (either POST or GET)
for backend modules. If anything was submitted a fallback to 0 is
integrated.

Change-Id: I683e4bb44fa86c2b40c6126d8360858a2319bebe
Fixes: #40796
Releases: 6.0
Reviewed-on: http://review.typo3.org/15826
Reviewed-by: Georg Ringer
Reviewed-by: Helmut Hummel
Tested-by: Helmut Hummel
typo3/sysext/extbase/Classes/Persistence/Generic/QuerySettingsInterface.php
typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbBackend.php
typo3/sysext/extbase/Classes/Persistence/Generic/Typo3QuerySettings.php
typo3/sysext/extbase/Tests/Unit/Persistence/Storage/Typo3DbBackendTest.php

index dc9c1fc..8952ac0 100644 (file)
@@ -80,6 +80,22 @@ interface QuerySettingsInterface
        public function getRespectSysLanguage();
 
        /**
+        * Sets the language uid for the language overlay.
+        *
+        * @param integer $sysLanguageUid language uid for the language overlay
+        * @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface instance of $this to allow method chaining
+        * @api
+        */
+       public function setSysLanguageUid($sysLanguageUid);
+
+       /**
+        * Returns the language uid for the language overlay
+        *
+        * @return integer language uid for the language overlay
+        */
+       public function getSysLanguageUid();
+
+       /**
         * Sets a flag indicating whether all or some enable fields should be ignored. If TRUE, all enable fields are ignored.
         * If--in addition to this--enableFieldsToBeIgnored is set, only fields specified there are ignored. If FALSE, all
         * enable fields are taken into account, regardless of the enableFieldsToBeIgnored setting.
index e441745..1e6c301 100644 (file)
@@ -270,7 +270,13 @@ class Typo3DbBackend implements \TYPO3\CMS\Extbase\Persistence\Generic\Storage\B
                $this->checkSqlErrors($sql);
                $rows = $this->getRowsFromResult($query->getSource(), $result);
                $this->databaseHandle->sql_free_result($result);
-               $rows = $this->doLanguageAndWorkspaceOverlay($query->getSource(), $rows);
+               // Get language uid from querySettings.
+               // Ensure the backend handling is not broken (fallback to Get parameter 'L' if needed)
+               $languageUid = NULL;
+               if ($query->getQuerySettings()->getSysLanguageUid()) {
+                       $languageUid = $query->getQuerySettings()->getSysLanguageUid();
+               }
+               $rows = $this->doLanguageAndWorkspaceOverlay($query->getSource(), $rows, $languageUid);
                // TODO: implement $objectData = $this->processObjectRecords($statementHandle);
                return $rows;
        }
@@ -805,7 +811,7 @@ class Typo3DbBackend implements \TYPO3\CMS\Extbase\Persistence\Generic\Storage\B
        protected function addAdditionalWhereClause(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings, $tableName, &$sql) {
                $this->addVisibilityConstraintStatement($querySettings, $tableName, $sql);
                if ($querySettings->getRespectSysLanguage()) {
-                       $this->addSysLanguageStatement($tableName, $sql);
+                       $this->addSysLanguageStatement($tableName, $sql, $querySettings->getSysLanguageUid());
                }
                if ($querySettings->getRespectStoragePage()) {
                        $this->addPageIdStatement($tableName, $sql, $querySettings->getStoragePageIds());
@@ -915,31 +921,28 @@ class Typo3DbBackend implements \TYPO3\CMS\Extbase\Persistence\Generic\Storage\B
         *
         * @param string $tableName The database table name
         * @param array &$sql The query parts
+        * @param integer $languageUid The language uid to pay attention
         * @return void
         */
-       protected function addSysLanguageStatement($tableName, array &$sql) {
+       protected function addSysLanguageStatement($tableName, array &$sql, $languageUid = 0) {
                if (is_array($GLOBALS['TCA'][$tableName]['ctrl'])) {
                        if (!empty($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])) {
                                // Select all entries for the current language
-                               if (isset($GLOBALS['TSFE']) && is_object($GLOBALS['TSFE'])) {
-                                       $additionalWhereClause = $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . ' IN (' . $GLOBALS['TSFE']->sys_language_uid . ',-1)';
-                                       // If any language is set -> get those entries which are not translated yet
-                                       // They will be removed by t3lib_page::getRecordOverlay if not matching overlay mode
-                                       if ($GLOBALS['TSFE']->sys_language_uid && isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])) {
-                                               $additionalWhereClause .= ' OR (' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0' .
-                                                       ' AND ' . $tableName . '.uid NOT IN (' . 'SELECT ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] .
-                                                       ' FROM ' . $tableName .
-                                                       ' WHERE ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] . '>0' .
-                                                       ' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '>0';
+                               $additionalWhereClause = $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . ' IN (' . intval($languageUid) . ',-1)';
+                               // If any language is set -> get those entries which are not translated yet
+                               // They will be removed by t3lib_page::getRecordOverlay if not matching overlay mode
+                               if (intval($languageUid) && isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])) {
+                                       $additionalWhereClause .= ' OR (' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0' .
+                                               ' AND ' . $tableName . '.uid NOT IN (' . 'SELECT ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] .
+                                               ' FROM ' . $tableName .
+                                               ' WHERE ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'] . '>0' .
+                                               ' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '>0';
 
-                                               // Add delete clause to ensure all entries are loaded
-                                               if (isset($GLOBALS['TCA'][$tableName]['ctrl']['delete'])) {
-                                                       $additionalWhereClause .= ' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['delete'] . '=0';
-                                               }
-                                               $additionalWhereClause .= '))';
+                                       // Add delete clause to ensure all entries are loaded
+                                       if (isset($GLOBALS['TCA'][$tableName]['ctrl']['delete'])) {
+                                               $additionalWhereClause .= ' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['delete'] . '=0';
                                        }
-                               } else {
-                                       $additionalWhereClause = $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . ' IN (0,-1)';
+                                       $additionalWhereClause .= '))';
                                }
                                $sql['additionalWhereClause'][] = '(' . $additionalWhereClause . ')';
                        }
index 4574a6e..5a94e3b 100644 (file)
@@ -80,6 +80,13 @@ class Typo3QuerySettings implements \TYPO3\CMS\Extbase\Persistence\Generic\Query
        protected $respectSysLanguage = TRUE;
 
        /**
+        * The language uid for the language overlay.
+        *
+        * @var integer
+        */
+       protected $sysLanguageUid = 0;
+
+       /**
         * Flag if the the query result should be returned as raw QueryResult.
         *
         * @var boolean
@@ -98,6 +105,14 @@ class Typo3QuerySettings implements \TYPO3\CMS\Extbase\Persistence\Generic\Query
                if (TYPO3_MODE === 'BE' && $configurationManager->isFeatureEnabled('ignoreAllEnableFieldsInBe')) {
                        $this->setIgnoreEnableFields(TRUE);
                }
+
+               // Set correct language uid for frontend handling
+               if (isset($GLOBALS['TSFE']) && is_object($GLOBALS['TSFE'])) {
+                       $this->setSysLanguageUid($GLOBALS['TSFE']->sys_language_content);
+               } elseif (intval(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('L'))) {
+                       // Set language from 'L' parameter
+                       $this->setSysLanguageUid(intval(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('L')));
+               }
        }
 
        /**
@@ -163,6 +178,26 @@ class Typo3QuerySettings implements \TYPO3\CMS\Extbase\Persistence\Generic\Query
        }
 
        /**
+        * Sets the language uid for the language overlay.
+        *
+        * @param integer $sysLanguageUid language uid for the language overlay
+        * @return \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface instance of $this to allow method chaining
+        * @api
+        */
+       public function setSysLanguageUid($sysLanguageUid) {
+               $this->sysLanguageUid = $sysLanguageUid;
+       }
+
+       /**
+        * Returns the language uid for the language overlay
+        *
+        * @return integer language uid for the language overlay
+        */
+       public function getSysLanguageUid() {
+               return $this->sysLanguageUid;
+       }
+
+       /**
         * Sets the flag if the visibility in the frontend should be respected.
         *
         * @param boolean $respectEnableFields TRUE if the visibility in the frontend should be respected. If TRUE, the "enable fields" of TYPO3 will be added to the query statement.
index f208db5..3411fdb 100644 (file)
@@ -129,12 +129,10 @@ class Typo3DbBackendTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
                        'languageField' => 'sys_language_uid',
                        'delete' => 'deleted'
                );
-               $tsfe = $this->getMock('TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController', array(), array(), '', false);
-               $tsfe->sys_language_uid = 0;
-               $GLOBALS['TSFE'] = $tsfe;
                $sql = array();
+               $languageUid = 0;
                $mockTypo3DbBackend = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Storage\\Typo3DbBackend', array('dummy'), array(), '', false);
-               $mockTypo3DbBackend->_callRef('addSysLanguageStatement', $table, $sql);
+               $mockTypo3DbBackend->_callRef('addSysLanguageStatement', $table, $sql, $languageUid);
                $expectedSql = array('additionalWhereClause' => array('(' . $table . '.sys_language_uid IN (0,-1))'));
                $this->assertSame($expectedSql, $sql);
        }
@@ -147,12 +145,10 @@ class Typo3DbBackendTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
                $GLOBALS['TCA'][$table]['ctrl'] = array(
                        'languageField' => 'sys_language_uid'
                );
-               $tsfe = $this->getMock('TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController', array(), array(), '', false);
-               $tsfe->sys_language_uid = 2;
-               $GLOBALS['TSFE'] = $tsfe;
                $sql = array();
+               $languageUid = 2;
                $mockTypo3DbBackend = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Storage\\Typo3DbBackend', array('dummy'), array(), '', false);
-               $mockTypo3DbBackend->_callRef('addSysLanguageStatement', $table, $sql);
+               $mockTypo3DbBackend->_callRef('addSysLanguageStatement', $table, $sql, $languageUid);
                $expectedSql = array('additionalWhereClause' => array('(' . $table . '.sys_language_uid IN (2,-1))'));
                $this->assertSame($expectedSql, $sql);
        }
@@ -166,12 +162,10 @@ class Typo3DbBackendTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
                        'languageField' => 'sys_language_uid',
                        'transOrigPointerField' => 'l10n_parent'
                );
-               $tsfe = $this->getMock('TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController', array(), array(), '', false);
-               $tsfe->sys_language_uid = 2;
-               $GLOBALS['TSFE'] = $tsfe;
                $sql = array();
+               $languageUid = 2;
                $mockTypo3DbBackend = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Storage\\Typo3DbBackend', array('dummy'), array(), '', false);
-               $mockTypo3DbBackend->_callRef('addSysLanguageStatement', $table, $sql);
+               $mockTypo3DbBackend->_callRef('addSysLanguageStatement', $table, $sql, $languageUid);
                $expectedSql = array('additionalWhereClause' => array('(' . $table . '.sys_language_uid IN (2,-1) OR (' . $table . '.sys_language_uid=0 AND ' . $table . '.uid NOT IN (SELECT ' . $table . '.l10n_parent FROM ' . $table . ' WHERE ' . $table . '.l10n_parent>0 AND ' . $table . '.sys_language_uid>0)))'));
                $this->assertSame($expectedSql, $sql);
        }
@@ -186,12 +180,35 @@ class Typo3DbBackendTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
                        'transOrigPointerField' => 'l10n_parent',
                        'delete' => 'deleted'
                );
-               $tsfe = $this->getMock('TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController', array(), array(), '', false);
-               $tsfe->sys_language_uid = 2;
-               $GLOBALS['TSFE'] = $tsfe;
                $sql = array();
+               $languageUid = 2;
                $mockTypo3DbBackend = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Storage\\Typo3DbBackend', array('dummy'), array(), '', false);
-               $mockTypo3DbBackend->_callRef('addSysLanguageStatement', $table, $sql);
+               $mockTypo3DbBackend->_callRef('addSysLanguageStatement', $table, $sql, $languageUid);
+               $expectedSql = array('additionalWhereClause' => array(
+                       '(' . $table . '.sys_language_uid IN (2,-1)' .
+                                       ' OR (' . $table . '.sys_language_uid=0 AND ' . $table . '.uid NOT IN (' .
+                                               'SELECT ' . $table . '.l10n_parent FROM ' . $table .
+                                               ' WHERE ' . $table . '.l10n_parent>0 AND ' .
+                                                       $table . '.sys_language_uid>0 AND ' .
+                                                       $table . '.deleted=0)))')
+               );
+               $this->assertSame($expectedSql, $sql);
+       }
+
+       /**
+        * @test
+        */
+       public function addSysLanguageStatementWorksInBackendContextWithSubselectionTakesDeleteStatementIntoAccountIfNecessary() {
+               $table = uniqid('tx_coretest_table');
+               $GLOBALS['TCA'][$table]['ctrl'] = array(
+                       'languageField' => 'sys_language_uid',
+                       'transOrigPointerField' => 'l10n_parent',
+                       'delete' => 'deleted'
+               );
+               $sql = array();
+               $languageUid = 2;
+               $mockTypo3DbBackend = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Storage\\Typo3DbBackend', array('dummy'), array(), '', false);
+               $mockTypo3DbBackend->_callRef('addSysLanguageStatement', $table, $sql, $languageUid);
                $expectedSql = array('additionalWhereClause' => array(
                        '(' . $table . '.sys_language_uid IN (2,-1)' .
                                        ' OR (' . $table . '.sys_language_uid=0 AND ' . $table . '.uid NOT IN (' .
@@ -422,4 +439,4 @@ class Typo3DbBackendTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
 }
 
 
-?>
\ No newline at end of file
+?>