[!!!][BUGFIX] Respect rootLevel -1 for extbase queries 75/43675/4
authorDaniel Goerz <ervaude@gmail.com>
Wed, 30 Sep 2015 22:25:29 +0000 (00:25 +0200)
committerBenni Mack <benni@typo3.org>
Thu, 8 Oct 2015 19:27:33 +0000 (21:27 +0200)
The rootLevel of a table can be configured to 0, 1 or -1.
Currently only 0 and 1 are respected by the Typo3DbQueryParser
when building the pageId statement. This patch streamlines
the statement building to work for -1 settings as well.

Change-Id: Ide900548ef90ea0f933f33640757b1cb20e8767e
Resolves: #63406
Releases: master
Reviewed-on: http://review.typo3.org/43675
Reviewed-by: Morton Jonuschat <m.jonuschat@mojocode.de>
Tested-by: Morton Jonuschat <m.jonuschat@mojocode.de>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
typo3/sysext/core/Documentation/Changelog/master/Breaking-63406-RespectRootlevelConfigurationinExtbaseQueries.rst [new file with mode: 0644]
typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbQueryParser.php
typo3/sysext/extbase/Tests/Unit/Persistence/Generic/Storage/Typo3DbQueryParserTest.php

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-63406-RespectRootlevelConfigurationinExtbaseQueries.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-63406-RespectRootlevelConfigurationinExtbaseQueries.rst
new file mode 100644 (file)
index 0000000..6747cd4
--- /dev/null
@@ -0,0 +1,36 @@
+=====================================================================
+Breaking: #63406 - Respect rootLevel configuration in extbase queries
+=====================================================================
+
+Description
+===========
+
+The rootLevel of a table can be configured to 0, 1 or -1 in TCA, to define where records of a table can be found in the system:
+
+* 0: In the page tree only
+* 1: Only on the root page (pid 0)
+* -1: Both, on the root page and in the page tree
+
+Currently only 0 and 1 are respected by the ``Typo3DbQueryParser`` when building the pageId statement. This means that a rootLevel of -1
+does not get any pageId statement at all and therefore ignores any ``storagePid`` configuration for extbase plugins.
+
+
+Impact
+======
+
+Custom records that have a configuration like this ``$GLOBALS['TCA']['tx_myext_domain_model_record']['ctrl']['rootLevel'] = -1`` and
+are used in extbase plugins might have trouble finding the records if ``plugin.tx_myext.persistence.storagePid`` is not configured properly.
+
+
+Affected Installations
+======================
+
+Third party code using ``$GLOBALS['TCA']['tx_myext_domain_model_record']['ctrl']['rootLevel'] = -1`` with records within the
+page tree and without a proper ``storagePid`` configuration.
+
+
+Migration
+=========
+
+Set ``plugin.tx_myext.persistence.storagePid`` to the page ids you want to find records from. 0 does not need to be included as
+it is added to the statement automatically.
index 0f51fe8..10544d7 100644 (file)
@@ -19,6 +19,7 @@ use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap;
 use TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface;
 use TYPO3\CMS\Extbase\Persistence\QueryInterface;
 use TYPO3\CMS\Extbase\Persistence\Generic\Qom;
 use TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface;
 use TYPO3\CMS\Extbase\Persistence\QueryInterface;
 use TYPO3\CMS\Extbase\Persistence\Generic\Qom;
+use TYPO3\CMS\Extbase\Persistence\Generic\Exception\InconsistentQuerySettingsException;
 
 /**
  * QueryParser, converting the qom to string representation
 
 /**
  * QueryParser, converting the qom to string representation
@@ -633,7 +634,7 @@ class Typo3DbQueryParser implements \TYPO3\CMS\Core\SingletonInterface {
         * @param array $enableFieldsToBeIgnored If $ignoreEnableFields is true, this array specifies enable fields to be ignored. If it is NULL or an empty array (default) all enable fields are ignored.
         * @param bool $includeDeleted A flag indicating whether deleted records should be included
         * @return string
         * @param array $enableFieldsToBeIgnored If $ignoreEnableFields is true, this array specifies enable fields to be ignored. If it is NULL or an empty array (default) all enable fields are ignored.
         * @param bool $includeDeleted A flag indicating whether deleted records should be included
         * @return string
-        * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InconsistentQuerySettingsException
+        * @throws InconsistentQuerySettingsException
         */
        protected function getFrontendConstraintStatement($tableName, $ignoreEnableFields, array $enableFieldsToBeIgnored = array(), $includeDeleted) {
                $statement = '';
         */
        protected function getFrontendConstraintStatement($tableName, $ignoreEnableFields, array $enableFieldsToBeIgnored = array(), $includeDeleted) {
                $statement = '';
@@ -647,7 +648,7 @@ class Typo3DbQueryParser implements \TYPO3\CMS\Core\SingletonInterface {
                } elseif (!$ignoreEnableFields && !$includeDeleted) {
                        $statement .= $this->getPageRepository()->enableFields($tableName);
                } elseif (!$ignoreEnableFields && $includeDeleted) {
                } elseif (!$ignoreEnableFields && !$includeDeleted) {
                        $statement .= $this->getPageRepository()->enableFields($tableName);
                } elseif (!$ignoreEnableFields && $includeDeleted) {
-                       throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InconsistentQuerySettingsException('Query setting "ignoreEnableFields=FALSE" can not be used together with "includeDeleted=TRUE" in frontend context.', 1327678173);
+                       throw new InconsistentQuerySettingsException('Query setting "ignoreEnableFields=FALSE" can not be used together with "includeDeleted=TRUE" in frontend context.', 1327678173);
                }
                return $statement;
        }
                }
                return $statement;
        }
@@ -727,7 +728,7 @@ class Typo3DbQueryParser implements \TYPO3\CMS\Core\SingletonInterface {
         * @param string $tableName The database table name
         * @param string $tableAlias The table alias used in the query.
         * @param array $storagePageIds list of storage page ids
         * @param string $tableName The database table name
         * @param string $tableAlias The table alias used in the query.
         * @param array $storagePageIds list of storage page ids
-        * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InconsistentQuerySettingsException
+        * @throws InconsistentQuerySettingsException
         * @return string
         */
        protected function getPageIdStatement($tableName, $tableAlias, array $storagePageIds) {
         * @return string
         */
        protected function getPageIdStatement($tableName, $tableAlias, array $storagePageIds) {
@@ -739,16 +740,28 @@ class Typo3DbQueryParser implements \TYPO3\CMS\Core\SingletonInterface {
                }
                if (is_array($GLOBALS['TCA'][$tableName]['ctrl']) && array_key_exists('pid', $tableColumns)) {
                        $rootLevel = (int)$GLOBALS['TCA'][$tableName]['ctrl']['rootLevel'];
                }
                if (is_array($GLOBALS['TCA'][$tableName]['ctrl']) && array_key_exists('pid', $tableColumns)) {
                        $rootLevel = (int)$GLOBALS['TCA'][$tableName]['ctrl']['rootLevel'];
-                       if ($rootLevel) {
-                               if ($rootLevel === 1) {
-                                       $pageIdStatement = $tableAlias . '.pid = 0';
-                               }
-                       } else {
-                               if (empty($storagePageIds)) {
-                                       throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InconsistentQuerySettingsException('Missing storage page ids.', 1365779762);
-                               }
-                               $pageIdStatement = $tableAlias . '.pid IN (' . implode(', ', $storagePageIds) . ')';
+                       switch ($rootLevel) {
+                               // Only in pid 0
+                               case 1:
+                                       return $tableAlias . '.pid = 0';
+                               // Pid 0 and pagetree
+                               case -1:
+                                       if (empty($storagePageIds)) {
+                                               return $tableAlias . '.pid = 0';
+                                       }
+                                       $storagePageIds[] = 0;
+                                       break;
+                               // Only pagetree or not set
+                               case 0:
+                                       if (empty($storagePageIds)) {
+                                               throw new InconsistentQuerySettingsException('Missing storage page ids.', 1365779762);
+                                       }
+                                       break;
+                               // Invalid configuration
+                               default:
+                                       return '';
                        }
                        }
+                       $pageIdStatement = $tableAlias . '.pid IN (' . implode(', ', $storagePageIds) . ')';
                }
                return $pageIdStatement;
        }
                }
                return $pageIdStatement;
        }
index cccd303..b734e06 100644 (file)
@@ -327,6 +327,7 @@ class Typo3DbQueryParserTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                $mockTypo3DbQueryParser->_callRef('getVisibilityConstraintStatement', $mockQuerySettings, $tableName, $tableName);
                unset($GLOBALS['TCA'][$tableName]);
        }
                $mockTypo3DbQueryParser->_callRef('getVisibilityConstraintStatement', $mockQuerySettings, $tableName, $tableName);
                unset($GLOBALS['TCA'][$tableName]);
        }
+
        /**
         * DataProvider for addPageIdStatement Tests
         */
        /**
         * DataProvider for addPageIdStatement Tests
         */
@@ -343,9 +344,20 @@ class Typo3DbQueryParserTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                                $table,
                                $table . '.pid IN (42, 27)'
                        ),
                                $table,
                                $table . '.pid IN (42, 27)'
                        ),
-                       'set no statement if rootLevel = -1' => array(
+                       'add 0 to given Pids if rootLevel = -1' => array(
+                               '-1',
+                               $table,
+                               $table . '.pid IN (42, 27, 0)'
+                       ),
+                       'set Pid to zero if rootLevel = -1 and no further pids given' => array(
                                '-1',
                                $table,
                                '-1',
                                $table,
+                               $table . '.pid = 0',
+                               array()
+                       ),
+                       'set no statement for invalid configuration' => array(
+                               '2',
+                               $table,
                                ''
                        )
                );
                                ''
                        )
                );
@@ -355,12 +367,11 @@ class Typo3DbQueryParserTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         * @dataProvider providerForAddPageIdStatementData
         */
         * @test
         * @dataProvider providerForAddPageIdStatementData
         */
-       public function addPageIdStatementSetsPidToZeroIfTableDeclaresRootlevel($rootLevel, $table, $expectedSql) {
+       public function addPageIdStatementSetsPidToZeroIfTableDeclaresRootlevel($rootLevel, $table, $expectedSql, $storagePageIds = array(42,27)) {
 
                $GLOBALS['TCA'][$table]['ctrl'] = array(
                        'rootLevel' => $rootLevel
                );
 
                $GLOBALS['TCA'][$table]['ctrl'] = array(
                        'rootLevel' => $rootLevel
                );
-               $storagePageIds = array(42,27);
                $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, array('dummy'), array(), '', FALSE);
                $mockFrontendVariableCache = $this->getMock(\TYPO3\CMS\Core\Cache\Frontend\VariableFrontend::class, array(), array(), '', FALSE);
                $mockTypo3DbQueryParser->_set('tableColumnCache', $mockFrontendVariableCache);
                $mockTypo3DbQueryParser = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class, array('dummy'), array(), '', FALSE);
                $mockFrontendVariableCache = $this->getMock(\TYPO3\CMS\Core\Cache\Frontend\VariableFrontend::class, array(), array(), '', FALSE);
                $mockTypo3DbQueryParser->_set('tableColumnCache', $mockFrontendVariableCache);