From 17a9651e5a7b08abcd0d962991e461dfe449b0bf Mon Sep 17 00:00:00 2001
From: Benni Mack <benni@typo3.org>
Date: Sun, 14 Aug 2016 19:34:17 +0200
Subject: [PATCH] [TASK] Doctrine: Migrate RTE-related Upgrade Wizards

Resolves: #77501
Releases: master
Change-Id: Ie66801fd8ba5ed411a7a0ad6eab84948e06c4c68
Reviewed-on: https://review.typo3.org/49480
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: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
---
 .../Hook/Install/DeprecatedRteProperties.php  | 100 ++++++++++++------
 .../RteAcronymButtonRenamedToAbbreviation.php |  68 +++++++-----
 2 files changed, 111 insertions(+), 57 deletions(-)

diff --git a/typo3/sysext/rtehtmlarea/Classes/Hook/Install/DeprecatedRteProperties.php b/typo3/sysext/rtehtmlarea/Classes/Hook/Install/DeprecatedRteProperties.php
index a9442e1e6311..6fbe1845939c 100644
--- a/typo3/sysext/rtehtmlarea/Classes/Hook/Install/DeprecatedRteProperties.php
+++ b/typo3/sysext/rtehtmlarea/Classes/Hook/Install/DeprecatedRteProperties.php
@@ -14,6 +14,10 @@ namespace TYPO3\CMS\Rtehtmlarea\Hook\Install;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Doctrine\DBAL\DBALException;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\StringUtility;
 use TYPO3\CMS\Install\Updates\AbstractUpdate;
 
 /**
@@ -102,7 +106,7 @@ class DeprecatedRteProperties extends AbstractUpdate
     {
         $result = false;
 
-        $pages = $this->getPagesWithDeprecatedRteProperties($dbQueries, $customMessages);
+        $pages = $this->getPagesWithDeprecatedRteProperties($customMessages);
         $pagesCount = count($pages);
         $deprecatedProperties = '';
         $deprecatedRteProperties = array_merge($this->replacementRteProperties, $this->useInsteadRteProperties);
@@ -165,7 +169,7 @@ class DeprecatedRteProperties extends AbstractUpdate
     public function performUpdate(array &$dbQueries, &$customMessages)
     {
         $customMessages = '';
-        $pages = $this->getPagesWithDeprecatedRteProperties($dbQueries, $customMessages);
+        $pages = $this->getPagesWithDeprecatedRteProperties($customMessages);
         if (empty($customMessages)) {
             $pagesCount = count($pages);
             if ($pagesCount) {
@@ -176,7 +180,7 @@ class DeprecatedRteProperties extends AbstractUpdate
                     if (empty($customMessages)) {
                         // If all pages were updated, we query again to check if any deprecated properties are still present.
                         if (count($updateablePages) === $pagesCount) {
-                            $pagesAfter = $this->getPagesWithDeprecatedRteProperties($dbQueries, $customMessages);
+                            $pagesAfter = $this->getPagesWithDeprecatedRteProperties($customMessages);
                             if (empty($customMessages)) {
                                 if (!empty($pagesAfter)) {
                                     $customMessages = 'Some deprecated Page TSconfig properties were found. However, the wizard was unable to automatically replace all the deprecated properties found. Some properties will have to be replaced manually.';
@@ -198,29 +202,66 @@ class DeprecatedRteProperties extends AbstractUpdate
     /**
      * Gets the pages with deprecated RTE properties in TSconfig column
      *
-     * @param array $dbQueries Pointer where to insert all DB queries made, so they can be shown to the user if wanted
      * @param string $customMessages Pointer to output custom messages
      * @return array uid and inclusion string for the pages with deprecated RTE properties in TSconfig column
      */
-    protected function getPagesWithDeprecatedRteProperties(&$dbQueries, &$customMessages)
+    protected function getPagesWithDeprecatedRteProperties(&$customMessages)
     {
-        $fields = 'uid, TSconfig';
-        $table = 'pages';
-        $where = '';
-        $db = $this->getDatabaseConnection();
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
+        $queryBuilder->getRestrictions()->removeAll();
+
+        $isMySQL = StringUtility::beginsWith($queryBuilder->getConnection()->getServerVersion(), 'MySQL');
+
+        $constraints = [];
         foreach (array_merge($this->replacementRteProperties, $this->useInsteadRteProperties, $this->doubleReplacementRteProperties) as $deprecatedRteProperty => $_) {
-            $where .= ($where ? ' OR ' : '') . '(TSconfig LIKE BINARY ' . $db->fullQuoteStr('%RTE.%' . $deprecatedRteProperty . '%', 'pages') . ' AND TSconfig NOT LIKE BINARY ' . $db->fullQuoteStr('%RTE.%' . $deprecatedRteProperty . 's%', 'pages') . ')' . LF;
-        }
-        $res = $db->exec_SELECTquery($fields, $table, $where);
-        $dbQueries[] = str_replace(LF, ' ', $db->debug_lastBuiltQuery);
-        if ($db->sql_error()) {
-            $customMessages = 'SQL-ERROR: ' . htmlspecialchars($db->sql_error());
+            // MySQL needs the non-standard BINARY modifier to ensure case sensitive comparisons with LIKE
+            if ($isMySQL) {
+                $constraints[] = $queryBuilder->expr()->andX(
+                    $queryBuilder->expr()->comparison(
+                        $queryBuilder->quoteIdentifier('TSconfig'),
+                        'LIKE BINARY',
+                        $queryBuilder->createNamedParameter(
+                            '%RTE.%' . $queryBuilder->escapeLikeWildcards($deprecatedRteProperty) . '%'
+                        )
+                    ),
+                    $queryBuilder->expr()->comparison(
+                        $queryBuilder->quoteIdentifier('TSconfig'),
+                        'NOT LIKE BINARY',
+                        $queryBuilder->createNamedParameter(
+                            '%RTE.%' . $queryBuilder->escapeLikeWildcards($deprecatedRteProperty) . 's%'
+                        )
+                    )
+                );
+            } else {
+                $constraints[] = $queryBuilder->expr()->andX(
+                    $queryBuilder->expr()->like(
+                        'TSconfig',
+                        $queryBuilder->createNamedParameter(
+                            '%RTE.%' . $queryBuilder->escapeLikeWildcards($deprecatedRteProperty) . '%'
+                        )
+                    ),
+                    $queryBuilder->expr()->notLike(
+                        'TSconfig',
+                        $queryBuilder->createNamedParameter(
+                            '%RTE.%' . $queryBuilder->escapeLikeWildcards($deprecatedRteProperty) . 's%'
+                        )
+                    )
+                );
+            }
         }
-        $pages = array();
-        while ($row = $db->sql_fetch_assoc($res)) {
-            $pages[] = $row;
+
+        try {
+            return $queryBuilder
+                ->select('uid', 'TSconfig')
+                ->from('pages')
+                ->orWhere(...$constraints)
+                ->execute()
+                ->fetchAll();
+        } catch (DBALException $e) {
+            $customMessages = 'SQL-ERROR: ' . htmlspecialchars($e->getPrevious()->getMessage());
         }
-        return $pages;
+
+        return [];
     }
 
     /**
@@ -235,7 +276,7 @@ class DeprecatedRteProperties extends AbstractUpdate
             $deprecatedProperties = explode(',', '/' . implode('/,/((RTE\\.(default\\.|config\\.[a-zA-Z0-9_\\-]*\\.[a-zA-Z0-9_\\-]*\\.))|\\s)', array_keys($this->replacementRteProperties)) . '/');
             $replacementProperties = explode(',', '$1' . implode(',$1', array_values($this->replacementRteProperties)));
             $updatedPageTSConfig = preg_replace($deprecatedProperties, $replacementProperties, $page['TSconfig']);
-            if ($updatedPageTSConfig == $page['TSconfig']) {
+            if ($updatedPageTSConfig === $page['TSconfig']) {
                 unset($pages[$index]);
             } else {
                 $pages[$index]['TSconfig'] = $updatedPageTSConfig;
@@ -253,18 +294,17 @@ class DeprecatedRteProperties extends AbstractUpdate
      */
     protected function updatePages($pages, &$dbQueries, &$customMessages)
     {
-        $db = $this->getDatabaseConnection();
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
         foreach ($pages as $page) {
-            $table = 'pages';
-            $where = 'uid =' . $page['uid'];
-            $field_values = array(
-                'TSconfig' => $page['TSconfig']
-            );
-            $db->exec_UPDATEquery($table, $where, $field_values);
-            $dbQueries[] = str_replace(LF, ' ', $db->debug_lastBuiltQuery);
-            if ($db->sql_error()) {
-                $customMessages .= 'SQL-ERROR: ' . htmlspecialchars($db->sql_error()) . LF . LF;
+            try {
+                $queryBuilder->update('pages')
+                    ->where($queryBuilder->expr()->eq('uid', (int)$page['uid']))
+                    ->set('TSconfig', $queryBuilder->quote($page['TSconfig']), false)
+                    ->execute();
+            } catch (DBALException $e) {
+                $customMessages .= 'SQL-ERROR: ' . htmlspecialchars($e->getPrevious()->getMessage()) . LF . LF;
             }
+            $dbQueries[] = str_replace(LF, ' ', $queryBuilder->getSQL());
         }
     }
 }
diff --git a/typo3/sysext/rtehtmlarea/Classes/Hook/Install/RteAcronymButtonRenamedToAbbreviation.php b/typo3/sysext/rtehtmlarea/Classes/Hook/Install/RteAcronymButtonRenamedToAbbreviation.php
index cbe2a94e357b..e97fdf4ad314 100644
--- a/typo3/sysext/rtehtmlarea/Classes/Hook/Install/RteAcronymButtonRenamedToAbbreviation.php
+++ b/typo3/sysext/rtehtmlarea/Classes/Hook/Install/RteAcronymButtonRenamedToAbbreviation.php
@@ -14,6 +14,10 @@ namespace TYPO3\CMS\Rtehtmlarea\Hook\Install;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Doctrine\DBAL\DBALException;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\StringUtility;
 use TYPO3\CMS\Install\Updates\AbstractUpdate;
 
 /**
@@ -37,7 +41,7 @@ class RteAcronymButtonRenamedToAbbreviation extends AbstractUpdate
     {
         $result = false;
 
-        $pages = $this->getPagesWithDeprecatedRteProperties($dbQueries, $customMessages);
+        $pages = $this->getPagesWithDeprecatedRteProperties($customMessages);
         $pagesCount = count($pages);
         $description = '<p>The RTE "acronym" button is deprecated and replaced by the "abbreviation" button since TYPO3 CMS 7.0.</p>' . LF . '<p>Page TSconfig currently includes the string "acronym" on <strong>' . strval($pagesCount) . '&nbsp;pages</strong>  (including deleted and hidden pages).</p>' . LF;
         if ($pagesCount) {
@@ -78,7 +82,7 @@ class RteAcronymButtonRenamedToAbbreviation extends AbstractUpdate
     public function performUpdate(array &$dbQueries, &$customMessages)
     {
         $customMessages = '';
-        $pages = $this->getPagesWithDeprecatedRteProperties($dbQueries, $customMessages);
+        $pages = $this->getPagesWithDeprecatedRteProperties($customMessages);
         if (empty($customMessages)) {
             $pagesCount = count($pages);
             if ($pagesCount) {
@@ -103,26 +107,37 @@ class RteAcronymButtonRenamedToAbbreviation extends AbstractUpdate
     /**
      * Gets the pages with deprecated RTE properties in TSconfig column
      *
-     * @param array $dbQueries Pointer where to insert all DB queries made, so they can be shown to the user if wanted
      * @param string $customMessages Pointer to output custom messages
      * @return array uid and inclusion string for the pages with deprecated RTE properties in TSconfig column
      */
-    protected function getPagesWithDeprecatedRteProperties(&$dbQueries, &$customMessages)
+    protected function getPagesWithDeprecatedRteProperties(&$customMessages)
     {
-        $db = $this->getDatabaseConnection();
-        $fields = 'uid, TSconfig';
-        $table = 'pages';
-        $where = 'TSconfig LIKE BINARY ' . $db->fullQuoteStr('%acronym%', 'pages');
-        $res = $db->exec_SELECTquery($fields, $table, $where);
-        $dbQueries[] = str_replace(LF, ' ', $db->debug_lastBuiltQuery);
-        if ($db->sql_error()) {
-            $customMessages = 'SQL-ERROR: ' . htmlspecialchars($db->sql_error());
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
+        $queryBuilder->getRestrictions()->removeAll();
+
+        $isMySQL = StringUtility::beginsWith($queryBuilder->getConnection()->getServerVersion(), 'MySQL');
+        if ($isMySQL) {
+            $whereClause = $queryBuilder->expr()->comparison(
+                $queryBuilder->quoteIdentifier('TSconfig'),
+                'LIKE BINARY',
+                $queryBuilder->createNamedParameter('%acronym%')
+            );
+        } else {
+            $whereClause = $queryBuilder->expr()->like('TSconfig', $queryBuilder->createNamedParameter('%acronym%'));
         }
-        $pages = array();
-        while ($row = $db->sql_fetch_assoc($res)) {
-            $pages[] = $row;
+
+        try {
+            return $queryBuilder
+                ->select('uid', 'TSconfig')
+                ->from('pages')
+                ->where($whereClause)
+                ->execute()
+                ->fetchAll();
+        } catch (DBALException $e) {
+            $customMessages = 'SQL-ERROR: ' . htmlspecialchars($e->getPrevious()->getMessage());
         }
-        return $pages;
+
+        return [];
     }
 
     /**
@@ -135,7 +150,7 @@ class RteAcronymButtonRenamedToAbbreviation extends AbstractUpdate
     {
         foreach ($pages as $index => $page) {
             $updatedPageTSConfig = str_replace('acronym', 'abbreviation', $page['TSconfig']);
-            if ($updatedPageTSConfig == $page['TSconfig']) {
+            if ($updatedPageTSConfig === $page['TSconfig']) {
                 unset($pages[$index]);
             } else {
                 $pages[$index]['TSconfig'] = $updatedPageTSConfig;
@@ -153,18 +168,17 @@ class RteAcronymButtonRenamedToAbbreviation extends AbstractUpdate
      */
     protected function updatePages($pages, &$dbQueries, &$customMessages)
     {
-        $db = $this->getDatabaseConnection();
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
         foreach ($pages as $page) {
-            $table = 'pages';
-            $where = 'uid =' . $page['uid'];
-            $field_values = array(
-                'TSconfig' => $page['TSconfig']
-            );
-            $db->exec_UPDATEquery($table, $where, $field_values);
-            $dbQueries[] = str_replace(LF, ' ', $db->debug_lastBuiltQuery);
-            if ($db->sql_error()) {
-                $customMessages .= 'SQL-ERROR: ' . htmlspecialchars($db->sql_error()) . LF . LF;
+            try {
+                $queryBuilder->update('pages')
+                    ->where($queryBuilder->expr()->eq('uid', (int)$page['uid']))
+                    ->set('TSconfig', $queryBuilder->quote($page['TSconfig']), false)
+                    ->execute();
+            } catch (DBALException $e) {
+                $customMessages .= 'SQL-ERROR: ' . htmlspecialchars($e->getPrevious()->getMessage()) . LF . LF;
             }
+            $dbQueries[] = str_replace(LF, ' ', $queryBuilder->getSQL());
         }
     }
 }
-- 
GitLab