Forked from maikschneider/GridelementsMigrationUpdate.php
Last active
March 23, 2023 10:42
-
-
Save JulianXIMA/da7235a8c86bb247aa1248f4a268b2a8 to your computer and use it in GitHub Desktop.
TYPO3 Gridelements to Container UpgradeWizard
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Xima\XmTemplatesNnfdav\Updates; | |
use Doctrine\DBAL\DBALException; | |
use Doctrine\DBAL\Driver\Exception; | |
use TYPO3\CMS\Core\Database\ConnectionPool; | |
use TYPO3\CMS\Core\Utility\GeneralUtility; | |
use TYPO3\CMS\Core\Utility\MathUtility; | |
use TYPO3\CMS\Install\Updates\DatabaseUpdatedPrerequisite; | |
use TYPO3\CMS\Install\Updates\RepeatableInterface; | |
use TYPO3\CMS\Install\Updates\UpgradeWizardInterface; | |
class GridelementsMigrationUpdate implements UpgradeWizardInterface, RepeatableInterface | |
{ | |
/** | |
* the individual mappings must be sorted like the values in the tx_gridelements_backend_layout field | |
* 'tx_gridelements_backend_layout' => [ | |
* 'container_identifier' => 'Enter CType for container-Ext here, e.g. container-2cols', | |
* 'children_map' => [ | |
* int value of tx_gridelements_columns => here the new colPos for container-Ext, | |
* ], | |
* 'flexform_tca_map' => [ | |
* 'projektteaser' => 'tx_myext_projectteaser', | |
* 'jobteaser' => 'tx_myext_jobteaser', | |
* 'breite' => 'tx_myext_blockwidth', | |
* ], | |
* ], | |
*/ | |
protected const MAPPING = [ | |
'1' => [ | |
'container_identifier' => 'container-2cols', | |
'container_view_column' => 0, | |
'children_map' => [ | |
10 => 200, | |
20 => 201, | |
], | |
], | |
'2' => [ | |
'container_identifier' => 'container-3cols', | |
'container_view_column' => 'null', | |
'children_map' => [ | |
10 => 202, | |
20 => 203, | |
30 => 204, | |
], | |
], | |
'3' => [ | |
'container_identifier' => 'container-2cols', | |
'container_view_column' => 1, | |
'children_map' => [ | |
10 => 200, | |
20 => 201, | |
], | |
], | |
]; | |
public function getIdentifier(): string | |
{ | |
return 'gridelements_migration'; | |
} | |
public function getTitle(): string | |
{ | |
return 'Gridelements to Container Migration'; | |
} | |
public function getDescription(): string | |
{ | |
return 'Migrate gridelements items to container'; | |
} | |
public function getPrerequisites(): array | |
{ | |
return [ | |
DatabaseUpdatedPrerequisite::class | |
]; | |
} | |
protected static function getSetStatementsFlexformMapping($flexformMapping) | |
{ | |
} | |
public function executeUpdate(): bool | |
{ | |
$sqls = []; | |
foreach (self::MAPPING as $layout => $mapping) { | |
// update flexform | |
$flexSql = "select uid, pi_flexform from tt_content where pi_flexform is not null and CType='gridelements_pi1' and tx_gridelements_backend_layout='" . $layout . "' and deleted=0;"; | |
$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tt_content'); | |
$flexformToMigrate = $connection->executeQuery($flexSql)->fetchAll(); | |
foreach ($flexformToMigrate as $row) { | |
$sqlSetStatements = []; | |
$flexData = \TYPO3\CMS\Core\Utility\GeneralUtility::xml2array($row['pi_flexform']); | |
foreach ($mapping['flexform_tca_map'] ?? [] as $flexName => $tcaName) { | |
$flexformValue = $flexData['data']['sDEF']['lDEF'][$flexName]['vDEF'] ?? ''; | |
if (!$flexformValue) { | |
continue; | |
} | |
$stringEscape = MathUtility::canBeInterpretedAsInteger($flexformValue) ? '' : '"'; | |
$sqlSetStatements[] = $tcaName . '=' . $stringEscape . $flexformValue . $stringEscape; | |
} | |
if (count($sqlSetStatements)) { | |
$sqls[] = 'update tt_content set ' . implode(', ', $sqlSetStatements) . ' where uid=' . $row['uid']; | |
} | |
} | |
// updates for CType and colPos | |
$sqls[] = "update tt_content set CType='" . $mapping['container_identifier'] . "', pi_flexform=null, view_column=" . $mapping['container_view_column'] . " where CType='gridelements_pi1' and tx_gridelements_backend_layout='" . $layout . "' and deleted=0;"; | |
foreach ($mapping['children_map'] as $oldId => $newId) { | |
$sqls[] = "update tt_content t1 inner join tt_content t2 on t1.tx_gridelements_container=t2.uid set t1.colPos=" . $newId . ", t1.tx_container_parent=t2.uid, t1.tx_gridelements_container=0, t1.tx_gridelements_columns=0 where t1.deleted=0 and t2.tx_gridelements_backend_layout='" . $layout . "' and t1.tx_gridelements_columns=" . $oldId . ";"; | |
} | |
// remove deleted gridelements | |
$sqls[] = 'delete from tt_content where CType="gridelements_pi1" and tx_gridelements_backend_layout="' . $layout . '" and deleted=1;'; | |
} | |
// remove all gridelements children with colPos = -1 which don't belong to any gridelements-container | |
$sqls[] = 'delete from tt_content where colPos = -1 and uid not in (select t1.uid from tt_content t1 inner join tt_content t2 on t1.tx_gridelements_container = t2.uid)'; | |
/** | |
* Fixes negative colPos to make db compare possible. There are some gridelements container which have "hidden" child-elements. | |
* They were created in a 3 column container, which later on was changed to a 2 column container. Means 1 element remains but is "hidden". | |
* These elements remain as "unused elements" after the migration from gridelements to container on the affected pages in the TYPO3 backend. | |
*/ | |
$sqls[] = 'update tt_content set colPos = 123 where colPos = -1;'; | |
foreach ($sqls as $sql) { | |
$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tt_content'); | |
$connection->executeQuery($sql); | |
} | |
return true; | |
} | |
/** | |
* Looks for tt_content elements that have a layout that should be migrated or with colPos = -1 | |
* @throws Exception | |
* @throws DBALException | |
*/ | |
public function updateNecessary(): bool | |
{ | |
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content'); | |
$queryBuilder->resetRestrictions(); | |
$conditions = []; | |
foreach (self::MAPPING as $layoutName => $mapping) { | |
$conditions[] = $queryBuilder->expr()->eq('tx_gridelements_backend_layout', | |
$queryBuilder->createNamedParameter($layoutName, \PDO::PARAM_STR)); | |
} | |
$elements = $queryBuilder->count('uid') | |
->from('tt_content') | |
->where( | |
$queryBuilder->expr()->or( | |
$queryBuilder->expr()->andX( | |
$queryBuilder->expr()->eq('CType', $queryBuilder->createNamedParameter('gridelements_pi1', | |
\PDO::PARAM_STR)), | |
$queryBuilder->expr()->orX(...$conditions) | |
), | |
$queryBuilder->expr()->eq('colPos', -1) | |
), | |
) | |
->execute() | |
->fetchOne(); | |
return (bool)$elements; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment