From b2ff42a6601bba70ac42e9561c132540088a1452 Mon Sep 17 00:00:00 2001 From: Thomas Hohn <thomas@hohn.dk> Date: Sat, 25 Feb 2017 12:25:11 +0100 Subject: [PATCH] [TASK] Upgrade wizard to merge fe_session_data to fe_sessions Added a upgrade wizard to merge fe_session_data to fe_sessions in order to avoid loosing session data when introducing the new session framework. Resolves: #79721 Releases: master Change-Id: Iee2eb9b3096d8916382c01d7d1ad90fcc150f397 Reviewed-on: https://review.typo3.org/51850 Reviewed-by: Morton Jonuschat <m.jonuschat@mojocode.de> Tested-by: Morton Jonuschat <m.jonuschat@mojocode.de> Tested-by: TYPO3com <no-reply@typo3.com> Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch> Tested-by: Christian Kuhn <lolli@schwarzbu.ch> --- .../Updates/MigrateFeSessionDataUpdate.php | 158 ++++++++++++++++++ typo3/sysext/install/ext_localconf.php | 2 + 2 files changed, 160 insertions(+) create mode 100644 typo3/sysext/install/Classes/Updates/MigrateFeSessionDataUpdate.php diff --git a/typo3/sysext/install/Classes/Updates/MigrateFeSessionDataUpdate.php b/typo3/sysext/install/Classes/Updates/MigrateFeSessionDataUpdate.php new file mode 100644 index 000000000000..340f54642058 --- /dev/null +++ b/typo3/sysext/install/Classes/Updates/MigrateFeSessionDataUpdate.php @@ -0,0 +1,158 @@ +<?php +declare(strict_types=1); +namespace TYPO3\CMS\Install\Updates; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +use Doctrine\DBAL\DBALException; +use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Utility\GeneralUtility; + +/** + * Merge sessions from old fe_session_data table into new structure from fe_sessions + */ +class MigrateFeSessionDataUpdate extends AbstractUpdate +{ + /** + * @var string + */ + protected $title = 'Migrates existing fe_session_data into fe_sessions'; + + /** + * Checks if an update is needed + * + * @param string $description The description for the update + * + * @return bool Whether an update is needed (true) or not (false) + */ + public function checkForUpdate(&$description) + { + if ($this->isWizardDone()) { + return false; + } + + if (!$this->checkIfTableExists('fe_session_data')) { + return false; + } + + $description = 'With the new Session Framwework the session data is stored in fe_sessions.</p>' + . ' <b>To avoid that data is truncated, ensure the columns of fe_sessions have been updated.</b></p>' + . ' This wizard migrates the existing data from fe_session_data into fe_sessions.' + . ' Existing entries in fe_sessions having an entry in fe_session_data are updated.' + . ' Entries in fe_session_data not found in fe_sessions are inserted with ses_anonymous = true'; + + // Check if there is data to migrate + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) + ->getQueryBuilderForTable('fe_session_data'); + $queryBuilder->getRestrictions()->removeAll(); + $count = $queryBuilder->count('*') + ->from('fe_session_data') + ->execute() + ->fetchColumn(0); + + return $count > 0; + } + + /** + * Moves data from fe_session_data into fe_sessions with respect to ses_anonymous + * + * @param array $databaseQueries Queries done in this update + * @param string $customMessage Custom messages + * @return bool + * @throws \Doctrine\DBAL\DBALException + */ + public function performUpdate(array &$databaseQueries, &$customMessage) + { + $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('fe_sessions'); + + // Process records that have entries in fe_sessions and fe_session_data + $queryBuilder = $connection->createQueryBuilder(); + $statement = $queryBuilder->select('fe_session_data.hash', 'fe_session_data.content') + ->from('fe_sessions') + ->join( + 'fe_sessions', + 'fe_session_data', + 'fe_session_data', + $queryBuilder->expr()->eq( + 'fe_sessions.ses_id', + $queryBuilder->quoteIdentifier('fe_session_data.hash') + ) + ) + ->execute(); + $databaseQueries[] = $queryBuilder->getSQL(); + + $updateQueryBuilder = $connection->createQueryBuilder(); + $updateQueryBuilder->update('fe_sessions') + ->where( + $updateQueryBuilder->expr()->eq( + 'ses_id', + $updateQueryBuilder->createPositionalParameter('', \PDO::PARAM_STR) + ) + ) + ->set('ses_data', $updateQueryBuilder->createPositionalParameter('', \PDO::PARAM_STR), false); + $databaseQueries[] = $updateQueryBuilder->getSQL(); + $updateStatement = $connection->prepare($updateQueryBuilder->getSQL()); + + $connection->beginTransaction(); + try { + while ($row = $statement->fetch()) { + $updateStatement->execute([$row['hash'], $row['content']]); + } + $connection->commit(); + } catch (DBALException $e) { + $connection->rollBack(); + throw $e; + } + + // Move records from fe_session_data that are not in fe_sessions + $queryBuilder = $connection->createQueryBuilder(); + $selectSQL = $queryBuilder->select('fe_session_data.hash', 'fe_session_data.content', 'fe_session_data.tstamp') + ->addSelectLiteral('1') + ->from('fe_session_data') + ->leftJoin( + 'fe_session_data', + 'fe_sessions', + 'fe_sessions', + $queryBuilder->expr()->eq( + 'fe_session_data.hash', + $queryBuilder->quoteIdentifier('fe_sessions.ses_id') + ) + ) + ->where($queryBuilder->expr()->isNull('fe_sessions.ses_id')) + ->getSQL(); + + $insertSQL = sprintf( + 'INSERT INTO %s(%s, %s, %s, %s) %s', + $connection->quoteIdentifier('fe_sessions'), + $connection->quoteIdentifier('ses_id'), + $connection->quoteIdentifier('ses_data'), + $connection->quoteIdentifier('ses_tstamp'), + $connection->quoteIdentifier('ses_anonymous'), + $selectSQL + ); + $databaseQueries[] = $insertSQL; + + try { + $connection->beginTransaction(); + $connection->exec($insertSQL); + $connection->commit(); + } catch (DBALException $e) { + $connection->rollBack(); + throw $e; + } + + $this->markWizardAsDone(); + return true; + } +} diff --git a/typo3/sysext/install/ext_localconf.php b/typo3/sysext/install/ext_localconf.php index afdfd8c5d2d9..d35928286338 100644 --- a/typo3/sysext/install/ext_localconf.php +++ b/typo3/sysext/install/ext_localconf.php @@ -66,3 +66,5 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'][\TYPO3\CMS\In = \TYPO3\CMS\Install\Updates\MigrateFscStaticTemplateUpdate::class; $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'][\TYPO3\CMS\Install\Updates\SysRefindexHashUpdater::class] = \TYPO3\CMS\Install\Updates\SysRefindexHashUpdater::class; +$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'][\TYPO3\CMS\Install\Updates\MigrateFeSessionDataUpdate::class] + = \TYPO3\CMS\Install\Updates\MigrateFeSessionDataUpdate::class; -- GitLab