ew_base/Classes/Updates/GridelementsToContainerService.php
Sebastian Fischer 5319bd35a5 First commit
2024-02-09 17:13:28 +01:00

269 lines
8.7 KiB
PHP
Executable File

<?php
declare(strict_types=1);
namespace Evoweb\EwBase\Updates;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\Database\Query\Restriction\EndTimeRestriction;
use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
use TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Service\FlexFormService;
use TYPO3\CMS\Core\Utility\ArrayUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['migrationResolveContainer'] = [];
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['migrationColPosOffset'] = 0;
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base']['migrationMapping'] = [
'130' => [
'CType' => 'three-col-columns',
],
'140' => [
'CType' => [
'search' => 'pi_flexform/type',
'matches' => [
0 => 'two-col-columns-11',
1 => 'two-col-columns-12',
2 => 'two-col-columns-21',
],
],
'map' => [
'pi_flexform/row_class' => 'frame_class',
]
],
];
*/
class GridelementsToContainerService
{
private const TABLE_NAME = 'tt_content';
protected array $resolveContainer = [];
protected int $colPosOffset = 0;
protected array $configuration = [];
public function __construct(
protected ConnectionPool $connectionPool,
protected DataHandler $dataHandler,
protected FlexFormService $flexFormService,
) {
$config =& $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ew_base'];
$this->resolveContainer = $config['migrationResolveContainer'] ?? [];
$this->colPosOffset = $config['migrationColPosOffset'] ?? 0;
$this->configuration = $config['migrationMapping'] ?? [];
}
public function migrate(): void
{
$this->initializeDataHandler();
// Move children out of container and remove container
foreach ($this->resolveContainer as $containerId) {
$this->resolveContainers((string)$containerId);
}
$this->migrateConfiguredContainer();
}
protected function initializeDataHandler(): void
{
$backendUser = GeneralUtility::makeInstance(BackendUserAuthentication::class);
$backendUser->user = [
'uid' => 0,
'admin' => 1,
];
$this->dataHandler->start([], [], $backendUser);
}
protected function resolveContainers(string $layout): void
{
$containers = $this->getGridElementsByLayout($layout);
foreach ($containers as $container) {
$this->processContainerResolve($container);
}
}
protected function processContainerResolve(array $container): void
{
$children = $this->getGridContainerChildren($container['uid']);
// move first child after container
$moveAfterThis = $container;
foreach ($children as $child) {
[$moveAfterThis, $container] = $this->processContainerResolveChild($child, $moveAfterThis, $container);
}
$this->deleteElement($container['uid']);
}
protected function processContainerResolveChild(array $child, array $moveAfterThis, array $container): array
{
$this->updateElement(
$child['uid'],
[
'tx_gridelements_container' => 0,
'colPos' => $container['colPos'],
'header' => $child['header'] ?: $container['header']
]
);
$this->moveElementAfterElement($child['uid'], $moveAfterThis['uid']);
// use this child to move the next child after
$moveAfterThis = $child;
// empty container header so only the first child gets the header
$container['header'] = '';
return [$moveAfterThis, $container];
}
protected function deleteElement(int $uid): void
{
$this->connectionPool
->getConnectionForTable(self::TABLE_NAME)
->update(self::TABLE_NAME, ['delete' => 1], ['uid' => $uid]);
}
protected function moveElementAfterElement(int $elementToMove, int $elementToMoveAfter): void
{
$this->dataHandler->moveRecord(self::TABLE_NAME, $elementToMove, $elementToMoveAfter * -1);
}
protected function migrateConfiguredContainer(): void
{
array_walk($this->configuration, function($config, $key) {
$containers = $this->getGridElementsByLayout((string)$key);
foreach ($containers as $container) {
$container['pi_flexform'] = $this->flexFormService->convertFlexFormContentToArray(
$container['pi_flexform']
);
$this->processContainerMigration($container, $config);
}
});
}
protected function processContainerMigration(array $container, array $config): void
{
$children = $this->getGridContainerChildren($container['uid']);
foreach ($children as $child) {
$this->processContainerMigrationChild($child, $container);
}
$data = [
'CType' => $this->getCType($container, $config),
'tx_gridelements_backend_layout' => ''
];
if (isset($config['map']) && is_array($config['map']) && !empty($container['pi_flexform'])) {
$data = $this->addMappedValues($data, $container, $config['map']);
}
$this->updateElement($container['uid'], $data);
}
protected function processContainerMigrationChild(array $child, array $container): void
{
$this->updateElement(
$child['uid'],
[
'hidden' => $child['hidden'] ?: $container['hidden'],
'colPos' => $child['tx_gridelements_columns'] + $this->colPosOffset,
'tx_container_parent' => $child['tx_gridelements_container'],
'tx_gridelements_columns' => 0,
'tx_gridelements_container' => 0,
]
);
}
protected function getCType(array $container, array $config): string
{
if (is_array($config['CType'])) {
$value = ArrayUtility::getValueByPath($container, $config['CType']['search']);
$result = $config['CType']['matches'][$value] ?? null;
} else {
$result = $config['CType'] ?? null;
}
if (empty($result)) {
throw new \Exception('CType must always be set');
}
return $result;
}
protected function addMappedValues(array $data, array $container, array $config): array
{
foreach ($config as $from => $to) {
try {
$value = ArrayUtility::getValueByPath($container, $from);
if (empty($container[$to]) && !empty($value)) {
$data[$to] = $value;
}
} catch (\throwable) {}
}
return $data;
}
protected function updateElement(int $uid, array $changes): void
{
$this->connectionPool
->getConnectionForTable(self::TABLE_NAME)
->update(self::TABLE_NAME, $changes, ['uid' => $uid]);
}
protected function getGridContainerChildren(int $containerUid): array
{
$queryBuilder = $this->getQueryBuilderForTable();
return $queryBuilder
->select('*')
->where(
$queryBuilder->expr()->eq(
'tx_gridelements_container',
$queryBuilder->createNamedParameter($containerUid, \PDO::PARAM_INT)
)
)
->orderBy('sorting')
->executeQuery()
->fetchAllAssociative();
}
protected function getGridElementsByLayout(string $layout): array
{
$queryBuilder = $this->getQueryBuilderForTable();
$expr = $queryBuilder->expr();
return $queryBuilder
->select('*')
->where(
$expr->eq('CType', $queryBuilder->createNamedParameter('gridelements_pi1')),
$expr->eq('tx_gridelements_backend_layout', $queryBuilder->createNamedParameter($layout))
)
->orderBy('sorting')
->executeQuery()
->fetchAllAssociative();
}
protected function getQueryBuilderForTable(string $table = 'tt_content'): QueryBuilder
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable($table);
$queryBuilder->getRestrictions()
->removeByType(HiddenRestriction::class)
->removeByType(StartTimeRestriction::class)
->removeByType(EndTimeRestriction::class);
$queryBuilder->from($table);
return $queryBuilder;
}
}