Created
January 20, 2025 08:18
-
-
Save thommyhh/7989c45db15245dbbb7533d0695a3383 to your computer and use it in GitHub Desktop.
Update image URLs for images in RTE fields in TYPO3 CMS
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 | |
declare(strict_types=1); | |
namespace MyVendor\MyPackage\Install; | |
use Netresearch\RteCKEditorImage\Database\RteImagesDbHook; | |
use Symfony\Contracts\Service\Attribute\Required; | |
use TYPO3\CMS\Backend\Resource\PublicUrlPrefixer; | |
use TYPO3\CMS\Core\Core\Bootstrap; | |
use TYPO3\CMS\Core\Core\Environment; | |
use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder; | |
use TYPO3\CMS\Core\Database\ConnectionPool; | |
use TYPO3\CMS\Core\DataHandling\DataHandler; | |
use TYPO3\CMS\Core\EventDispatcher\ListenerProvider; | |
use TYPO3\CMS\Core\Html\RteHtmlParser; | |
use TYPO3\CMS\Core\Resource\Event\GeneratePublicUrlForResourceEvent; | |
use TYPO3\CMS\Core\Site\SiteFinder; | |
use TYPO3\CMS\Core\Utility\GeneralUtility; | |
use TYPO3\CMS\Install\Attribute\UpgradeWizard; | |
use TYPO3\CMS\Install\Updates\DatabaseUpdatedPrerequisite; | |
use TYPO3\CMS\Install\Updates\UpgradeWizardInterface; | |
#[UpgradeWizard('rte_image_url_upgrade')] | |
class RteImageUrlUpgradeWizard implements UpgradeWizardInterface | |
{ | |
protected $title = 'RTE Image Upgrade Wizard'; | |
protected $description = 'Fix URLs for images in RTE fields'; | |
protected RteImagesDbHook $rteImagesDbHook; | |
protected RteHtmlParser $rteHtmlParser; | |
protected DataHandler $dataHandler; | |
protected ListenerProvider $listenerProvider; | |
#[Required] | |
public function setRteImagesDbHook(RteImagesDbHook $rteImagesDbHook): void | |
{ | |
$this->rteImagesDbHook = $rteImagesDbHook; | |
} | |
#[Required] | |
public function setRteHtmlParser(RteHtmlParser $rteHtmlParser): void | |
{ | |
$this->rteHtmlParser = $rteHtmlParser; | |
} | |
#[Required] | |
public function setDataHandler(DataHandler $dataHandler): void | |
{ | |
$this->dataHandler = $dataHandler; | |
} | |
#[Required] | |
public function setListenerProvider(ListenerProvider $listenerProvider): void | |
{ | |
$this->listenerProvider = $listenerProvider; | |
$this->listenerProvider->addListener(GeneratePublicUrlForResourceEvent::class, PublicUrlPrefixer::class, 'prefixWithSitePath'); | |
} | |
public function getTitle(): string | |
{ | |
return $this->title; | |
} | |
public function getDescription(): string | |
{ | |
return $this->description; | |
} | |
public function executeUpdate(): bool | |
{ | |
$backupRequest = $GLOBALS['TYPO3_REQUEST'] ?? null; | |
// Find site `main` | |
$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByIdentifier('main'); | |
// Fake backend request to make sure RTE images are processed | |
/** @var \TYPO3\CMS\Core\Http\ServerRequest $request */ | |
$request = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Http\ServerRequest::class); | |
$request = $request->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_BE) | |
->withUri($site->getBase()->withPath('/typo3/index.php')); | |
$GLOBALS['TYPO3_REQUEST'] = $request; | |
Bootstrap::initializeBackendUser(request: $request); | |
$GLOBALS['BE_USER']->user['admin'] = 1; | |
foreach ($GLOBALS['TCA'] as $tableName => $tableConfiguration) { | |
$fieldsToFetch = []; | |
foreach ($tableConfiguration['columns'] as $fieldName => $fieldConfiguration) { | |
if ($fieldConfiguration['config']['type'] === 'text' && ($fieldConfiguration['config']['enableRichtext'] ?? false)) { | |
$fieldsToFetch[] = $fieldName; | |
} | |
} | |
if (!empty($fieldsToFetch)) { | |
$this->processRecords($tableName, $fieldsToFetch); | |
} | |
if ($GLOBALS['TCA'][$tableName]['ctrl']['type'] ?? false) { | |
foreach ($tableConfiguration['types'] as $type => $typeConfiguration) { | |
$fieldsToFetch = []; | |
foreach ($typeConfiguration['columnsOverrides'] ?? [] as $fieldName => $fieldConfiguration) { | |
if ($fieldConfiguration['config']['enableRichtext'] ?? false) { | |
$fieldsToFetch[] = $fieldName; | |
} | |
} | |
if (!empty($fieldsToFetch)) { | |
$this->processRecords($tableName, $fieldsToFetch, $type); | |
} | |
} | |
} | |
} | |
if ($backupRequest) { | |
$GLOBALS['TYPO3_REQUEST'] = $backupRequest; | |
} | |
return true; | |
} | |
protected function processRecords(string $table, array $fieldsToFetch, ?string $type = null): void | |
{ | |
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table); | |
$queryBuilder->getRestrictions()->removeAll(); | |
$queryBuilder | |
->select('uid', ...$fieldsToFetch) | |
->from($table); | |
if ($type) { | |
$queryBuilder->addSelect($GLOBALS['TCA'][$table]['ctrl']['type']); | |
$queryBuilder->where( | |
$queryBuilder->expr()->eq($GLOBALS['TCA'][$table]['ctrl']['type'], $queryBuilder->createNamedParameter($type)) | |
); | |
} | |
$updateQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table); | |
$updateQueryBuilder->update($table) | |
->where( | |
$updateQueryBuilder->expr()->eq('uid', $updateQueryBuilder->createNamedParameter('', \PDO::PARAM_INT, ':uid')) | |
); | |
foreach ($fieldsToFetch as $fieldName) { | |
if ($fieldName !== 'uid') { | |
$updateQueryBuilder->set($fieldName, $updateQueryBuilder->createNamedParameter('', \PDO::PARAM_STR, ':' . $fieldName), false); | |
} | |
} | |
foreach ($queryBuilder->executeQuery()->fetchAllAssociative() as $record) { | |
$incomingData = $record; | |
$this->dataHandler->checkValue_currentRecord = $record; | |
$this->rteImagesDbHook->processDatamap_postProcessFieldArray('update', $table, (string) $record['uid'], $record, $this->dataHandler); | |
if (count(array_diff($incomingData, $record)) > 0) { | |
foreach ($fieldsToFetch as $fieldName) { | |
if (!empty($record[$fieldName])) { | |
$updateQueryBuilder->setParameter($fieldName, $record[$fieldName]); | |
} | |
} | |
$updateQueryBuilder->setParameter('uid', $record['uid']); | |
$updateQueryBuilder->executeStatement(); | |
} | |
} | |
} | |
public function updateNecessary(): bool | |
{ | |
return !Environment::isCli(); | |
} | |
public function getPrerequisites(): array | |
{ | |
return [DatabaseUpdatedPrerequisite::class]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment