[TASK] Doctrine: Migrate PlainDataResolver 69/49269/8
authorWouter Wolters <typo3@wouterwolters.nl>
Fri, 29 Jul 2016 14:53:36 +0000 (16:53 +0200)
committerOliver Hader <oliver.hader@typo3.org>
Thu, 4 Aug 2016 21:08:52 +0000 (23:08 +0200)
Resolves: #77311
Releases: master
Change-Id: I83a354515142390a839b7ab309fa1a7f83b65e12
Reviewed-on: https://review.typo3.org/49269
Tested-by: Bamboo TYPO3com <info@typo3.com>
Reviewed-by: Morton Jonuschat <m.jonuschat@mojocode.de>
Tested-by: Morton Jonuschat <m.jonuschat@mojocode.de>
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: Georg Ringer <georg.ringer@gmail.com>
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: Oliver Hader <oliver.hader@typo3.org>
typo3/sysext/core/Classes/DataHandling/DataHandler.php
typo3/sysext/core/Classes/DataHandling/PlainDataResolver.php
typo3/sysext/core/Classes/Database/RelationHandler.php

index ca99dd5..47d69d8 100644 (file)
@@ -8267,12 +8267,14 @@ class DataHandler
      */
     protected function resolveVersionedRecords($tableName, $fieldNames, $sortingField, array $liveIds)
     {
+        $connection = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getConnectionForTable($tableName);
         /** @var PlainDataResolver $resolver */
         $resolver = GeneralUtility::makeInstance(
             PlainDataResolver::class,
             $tableName,
             $liveIds,
-            $sortingField
+            [$connection->quoteIdentifier($sortingField)]
         );
 
         $resolver->setWorkspaceId($this->BE_USER->workspace);
index 3fd1e12..cbd749e 100644 (file)
@@ -15,6 +15,8 @@ namespace TYPO3\CMS\Core\DataHandling;
  */
 
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Versioning\VersionState;
 
 /**
@@ -37,7 +39,7 @@ class PlainDataResolver
     protected $liveIds;
 
     /**
-     * @var string
+     * @var array
      */
     protected $sortingStatement;
 
@@ -69,9 +71,9 @@ class PlainDataResolver
     /**
      * @param string $tableName
      * @param int[] $liveIds
-     * @param NULL|string $sortingStatement
+     * @param NULL|array $sortingStatement
      */
-    public function __construct($tableName, array $liveIds, $sortingStatement = null)
+    public function __construct($tableName, array $liveIds, array $sortingStatement = null)
     {
         $this->tableName = $tableName;
         $this->liveIds = $this->reindex($liveIds);
@@ -148,27 +150,35 @@ class PlainDataResolver
         }
 
         $ids = $this->processVersionMovePlaceholders($ids);
-        $versions = $this->getDatabaseConnection()->exec_SELECTgetRows(
-            'uid,t3ver_oid,t3ver_state',
-            $this->tableName,
-            'pid=-1 AND t3ver_oid IN (' . $this->intImplode(',', $ids) . ')'
-            . ' AND t3ver_wsid=' . $this->workspaceId
-        );
-
-        if (!empty($versions)) {
-            foreach ($versions as $version) {
-                $liveReferenceId = $version['t3ver_oid'];
-                $versionId = $version['uid'];
-                if (isset($ids[$liveReferenceId])) {
-                    if (!$this->keepDeletePlaceholder && VersionState::cast($version['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) {
-                        unset($ids[$liveReferenceId]);
-                    } else {
-                        $ids[$liveReferenceId] = $versionId;
-                    }
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getQueryBuilderForTable($this->tableName);
+
+        $queryBuilder->getRestrictions()->removeAll();
+
+        $result = $queryBuilder
+            ->select('uid', 't3ver_oid', 't3ver_state')
+            ->from($this->tableName)
+            ->where(
+                $queryBuilder->expr()->eq('pid', -1),
+                $queryBuilder->expr()->in('t3ver_oid', array_map('intval', $ids)),
+                $queryBuilder->expr()->eq('t3ver_wsid', $this->workspaceId)
+            )
+            ->execute();
+
+        while ($version = $result->fetch()) {
+            $liveReferenceId = $version['t3ver_oid'];
+            $versionId = $version['uid'];
+            if (isset($ids[$liveReferenceId])) {
+                if (!$this->keepDeletePlaceholder
+                    && VersionState::cast($version['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)
+                ) {
+                    unset($ids[$liveReferenceId]);
+                } else {
+                    $ids[$liveReferenceId] = $versionId;
                 }
             }
-            $ids = $this->reindex($ids);
         }
+        $ids = $this->reindex($ids);
 
         return $ids;
     }
@@ -186,30 +196,37 @@ class PlainDataResolver
             return $ids;
         }
 
-        $movePlaceholders = $this->getDatabaseConnection()->exec_SELECTgetRows(
-            'uid,t3ver_move_id',
-            $this->tableName,
-            'pid<>-1 AND t3ver_state=' . VersionState::MOVE_PLACEHOLDER
-            . ' AND t3ver_wsid=' . $this->workspaceId
-            . ' AND t3ver_move_id IN (' . $this->intImplode(',', $ids) . ')'
-        );
-
-        if (!empty($movePlaceholders)) {
-            foreach ($movePlaceholders as $movePlaceholder) {
-                $liveReferenceId = $movePlaceholder['t3ver_move_id'];
-                $movePlaceholderId = $movePlaceholder['uid'];
-                // Substitute MOVE_PLACEHOLDER and purge live reference
-                if (isset($ids[$movePlaceholderId])) {
-                    $ids[$movePlaceholderId] = $liveReferenceId;
-                    unset($ids[$liveReferenceId]);
-                // Just purge live reference
-                } elseif (!$this->keepMovePlaceholder) {
-                    unset($ids[$liveReferenceId]);
-                }
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getQueryBuilderForTable($this->tableName);
+
+        $queryBuilder->getRestrictions()->removeAll();
+
+        $result = $queryBuilder
+            ->select('uid', 't3ver_move_id')
+            ->from($this->tableName)
+            ->where(
+                $queryBuilder->expr()->neq('pid', -1),
+                $queryBuilder->expr()->eq('t3ver_state', VersionState::MOVE_PLACEHOLDER),
+                $queryBuilder->expr()->eq('t3ver_wsid', $this->workspaceId),
+                $queryBuilder->expr()->in('t3ver_move_id', array_map('intval', $ids))
+            )
+            ->execute();
+
+        while ($movePlaceholder = $result->fetch()) {
+            $liveReferenceId = $movePlaceholder['t3ver_move_id'];
+            $movePlaceholderId = $movePlaceholder['uid'];
+            // Substitute MOVE_PLACEHOLDER and purge live reference
+            if (isset($ids[$movePlaceholderId])) {
+                $ids[$movePlaceholderId] = $liveReferenceId;
+                unset($ids[$liveReferenceId]);
+            // Just purge live reference
+            } elseif (!$this->keepMovePlaceholder) {
+                unset($ids[$liveReferenceId]);
             }
-            $ids = $this->reindex($ids);
         }
 
+        $ids = $this->reindex($ids);
+
         return $ids;
     }
 
@@ -227,22 +244,27 @@ class PlainDataResolver
             return $ids;
         }
 
-        $records = $this->getDatabaseConnection()->exec_SELECTgetRows(
-            'uid',
-            $this->tableName,
-            'uid IN (' . $this->intImplode(',', $ids) . ')',
-            '',
-            $this->sortingStatement,
-            '',
-            'uid'
-        );
-
-        if (!is_array($records)) {
-            return array();
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getQueryBuilderForTable($this->tableName);
+
+        $queryBuilder->getRestrictions()->removeAll();
+
+        $queryBuilder
+            ->select('uid')
+            ->from($this->tableName)
+            ->where(
+                $queryBuilder->expr()->in('uid', array_map('intval', $ids))
+            );
+
+        if (!empty($this->sortingStatement)) {
+            foreach ($this->sortingStatement as $sortingStatement) {
+                $queryBuilder->add('orderBy', $sortingStatement, true);
+            }
         }
 
-        $ids = $this->reindex(array_keys($records));
-        return $ids;
+        $sortedIds = $queryBuilder->execute()->fetchAll();
+
+        return $this->reindex(array_column($sortedIds, 'uid'));
     }
 
     /**
@@ -259,28 +281,32 @@ class PlainDataResolver
             return $ids;
         }
 
-        $records = $this->getDatabaseConnection()->exec_SELECTgetRows(
-            'uid,t3ver_oid',
-            $this->tableName,
-            'uid IN (' . $this->intImplode(',', $ids) . ')',
-            '',
-            '',
-            '',
-            'uid'
-        );
-
-        if (!is_array($records)) {
-            return array();
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getQueryBuilderForTable($this->tableName);
+
+        $queryBuilder->getRestrictions()->removeAll();
+
+        $result = $queryBuilder
+            ->select('uid', 't3ver_oid')
+            ->from($this->tableName)
+            ->where(
+                $queryBuilder->expr()->in('uid', array_map('intval', $ids))
+            )
+            ->execute();
+
+        $versionIds = [];
+        while ($record = $result->fetch()) {
+            $liveId = $record['uid'];
+            $versionIds[$liveId] = $record['t3ver_oid'];
         }
 
         foreach ($ids as $id) {
-            if (!empty($records[$id]['t3ver_oid'])) {
-                $ids[$id] = $records[$id]['t3ver_oid'];
+            if (!empty($versionIds[$id])) {
+                $ids[$id] = $versionIds[$id];
             }
         }
 
-        $ids = $this->reindex($ids);
-        return $ids;
+        return $this->reindex($ids);
     }
 
     /**
@@ -314,24 +340,4 @@ class PlainDataResolver
     {
         return BackendUtility::isTableLocalizable($this->tableName);
     }
-
-    /**
-     * Implodes an array of casted integer values.
-     *
-     * @param string $delimiter
-     * @param array $values
-     * @return string
-     */
-    protected function intImplode($delimiter, array $values)
-    {
-        return implode($delimiter, array_map('intval', $values));
-    }
-
-    /**
-     * @return \TYPO3\CMS\Core\Database\DatabaseConnection
-     */
-    protected function getDatabaseConnection()
-    {
-        return $GLOBALS['TYPO3_DB'];
-    }
 }
index f2f8e0f..3827f0c 100644 (file)
@@ -15,6 +15,8 @@ namespace TYPO3\CMS\Core\Database;
  */
 
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Database\Query\QueryHelper;
+use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
 use TYPO3\CMS\Core\DataHandling\PlainDataResolver;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
@@ -769,29 +771,51 @@ class RelationHandler
         $foreign_table_field = $conf['foreign_table_field'];
         $useDeleteClause = !$this->undeleteRecord;
         $foreign_match_fields = is_array($conf['foreign_match_fields']) ? $conf['foreign_match_fields'] : array();
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getQueryBuilderForTable($foreign_table);
+        $queryBuilder->getRestrictions()
+            ->removeAll();
+        // Use the deleteClause (e.g. "deleted=0") on this table
+        if ($useDeleteClause) {
+            $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
+        }
+
+        $queryBuilder->select('uid')
+            ->from($foreign_table);
+
         // Search for $uid in foreign_field, and if we have symmetric relations, do this also on symmetric_field
         if ($conf['symmetric_field']) {
-            $whereClause = '(' . $conf['foreign_field'] . '=' . $uid . ' OR ' . $conf['symmetric_field'] . '=' . $uid . ')';
+            $queryBuilder->where(
+                $queryBuilder->expr()->orX(
+                    $queryBuilder->expr()->eq($conf['foreign_field'], $uid),
+                    $queryBuilder->expr()->eq($conf['symmetric_field'], $uid)
+                )
+            );
         } else {
-            $whereClause = $conf['foreign_field'] . '=' . $uid;
-        }
-        // Use the deleteClause (e.g. "deleted=0") on this table
-        if ($useDeleteClause) {
-            $whereClause .= BackendUtility::deleteClause($foreign_table);
+            $queryBuilder->where($queryBuilder->expr()->eq($conf['foreign_field'], $uid));
         }
         // If it's requested to look for the parent uid AND the parent table,
         // add an additional SQL-WHERE clause
         if ($foreign_table_field && $this->currentTable) {
-            $whereClause .= ' AND ' . $foreign_table_field . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->currentTable, $foreign_table);
+            $queryBuilder->andWhere(
+                $queryBuilder->expr()->eq(
+                    $foreign_table_field,
+                    $queryBuilder->createNamedParameter($this->currentTable)
+                )
+            );
         }
         // Add additional where clause if foreign_match_fields are defined
         foreach ($foreign_match_fields as $field => $value) {
-            $whereClause .= ' AND ' . $field . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($value, $foreign_table);
+            $queryBuilder->andWhere(
+                $queryBuilder->expr()->eq($field, $queryBuilder->createNamedParameter($value))
+            );
         }
         // Select children from the live(!) workspace only
         if (BackendUtility::isTableWorkspaceEnabled($foreign_table)) {
-            $workspaceList = '0,' . $this->getWorkspaceId();
-            $whereClause .= ' AND ' . $foreign_table . '.t3ver_wsid IN (' . $workspaceList . ') AND ' . $foreign_table . '.pid<>-1';
+            $queryBuilder->andWhere(
+                $queryBuilder->expr()->in($foreign_table . '.t3ver_wsid', [0, (int)$this->getWorkspaceId()]),
+                $queryBuilder->expr()->neq($foreign_table . '.pid', -1)
+            );
         }
         // Get the correct sorting field
         // Specific manual sortby for data handled by this field
@@ -799,12 +823,15 @@ class RelationHandler
         if ($conf['foreign_sortby']) {
             if ($conf['symmetric_sortby'] && $conf['symmetric_field']) {
                 // Sorting depends on, from which side of the relation we're looking at it
-                $sortby = '
-                                       CASE
-                                               WHEN ' . $conf['foreign_field'] . '=' . $uid . '
-                                               THEN ' . $conf['foreign_sortby'] . '
-                                               ELSE ' . $conf['symmetric_sortby'] . '
-                                       END';
+                // This requires bypassing automatic quoting and setting of the default sort direction
+                $queryBuilder->add(
+                    'orderBy',
+                    'CASE
+                                               WHEN ' . $queryBuilder->expr()->eq($conf['foreign_field'], $uid) . '
+                                               THEN ' . $queryBuilder->quoteIdentifier($conf['foreign_sortby']) . '
+                                               ELSE ' . $queryBuilder->quoteIdentifier($conf['symmetric_sortby']) . '
+                                       END'
+                );
             } else {
                 // Regular single-side behaviour
                 $sortby = $conf['foreign_sortby'];
@@ -819,11 +846,23 @@ class RelationHandler
             // Default sortby for all table records
             $sortby = $GLOBALS['TCA'][$foreign_table]['ctrl']['default_sortby'];
         }
-        // Strip a possible "ORDER BY" in front of the $sortby value
-        $sortby = $GLOBALS['TYPO3_DB']->stripOrderBy($sortby);
+
+        if (!empty($sortby)) {
+            foreach (QueryHelper::parseOrderBy($sortby) as $orderPair) {
+                list($fieldName, $sorting) = $orderPair;
+                $queryBuilder->addOrderBy($fieldName, $sorting);
+            }
+        }
+
         // Get the rows from storage
-        $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid', $foreign_table, $whereClause, '', $sortby, '', 'uid');
+        $rows = [];
+        $result = $queryBuilder->execute();
+        while ($row = $result->fetch()) {
+            $rows[$row['uid']] = $row;
+        }
         if (!empty($rows)) {
+            // Retrieve the parsed and prepared ORDER BY configuration for the resolver
+            $sortby = $queryBuilder->getQueryPart('orderBy');
             $ids = $this->getResolver($foreign_table, array_keys($rows), $sortby)->get();
             foreach ($ids as $id) {
                 $this->itemArray[$key]['id'] = $id;
@@ -1336,10 +1375,10 @@ class RelationHandler
     /**
      * @param string $tableName
      * @param int[] $ids
-     * @param string $sortingStatement
+     * @param array $sortingStatement
      * @return PlainDataResolver
      */
-    protected function getResolver($tableName, array $ids, $sortingStatement = null)
+    protected function getResolver($tableName, array $ids, array $sortingStatement = null)
     {
         /** @var PlainDataResolver $resolver */
         $resolver = GeneralUtility::makeInstance(