Skip to content

Instantly share code, notes, and snippets.

@nicodh
Last active December 19, 2015 08:29
Show Gist options
  • Save nicodh/5926450 to your computer and use it in GitHub Desktop.
Save nicodh/5926450 to your computer and use it in GitHub Desktop.
Update wizard for file links in RTE fields. Migrates links like <link fileadmin/download.pdf download >Download</link> to <link file:123 download >Download</link>
<?php
namespace TYPO3\CMS\Install\Updates;
/***************************************************************
* Copyright notice
*
* (c) 2013 Nico de Haen
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Upgrade wizard which goes through tt_content records
* and replaces links with a path reference with the according sys_file reference
*
* @author Nico de Haen
* @license http://www.gnu.org/copyleft/gpl.html
*/
class RteFileLinksUpdateWizard extends \TYPO3\CMS\Install\Updates\AbstractUpdate {
/**
* @var string
*/
protected $title = 'Migrate file relations of tt_content "bodytext"';
/*
* @var \TYPO3\CMS\Core\Html\RteHtmlParser
*/
protected $rteHtmlParser;
/**
* should we include deleted content elements here?
*
* @var string
*/
protected $addWhere = 'bodytext RLIKE "<link[[:space:]]*([[:alnum:]]|_|-)*/" AND deleted = 0';
/**
* @var int
*/
protected $convertedLinkCounter = 0;
/**
*
* @var array
*/
protected $fileNotFoundErrors = array();
/**
* Reference to the current record
* to enable meaningful error messages in recursion method
* @var null|array
*/
protected $currentRecord = NULL;
/**
* The default storage
* @var \TYPO3\CMS\Core\Resource\ResourceStorage
*/
protected $storage = NULL;
protected $fileAdminDir;
/**
* Initialize all required repository and factory objects.
*
* @throws \RuntimeException
*/
protected function init() {
$this->rteHtmlParser = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Html\\RteHtmlParser');
$storageRepository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\StorageRepository');
$storages = $storageRepository->findAll();
$this->storage = $storages[0];
$this->fileAdminDir = $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'];
}
/**
* Checks if an update is needed
*
* @param string &$description: The description for the update
* @return boolean TRUE if an update is needed, FALSE otherwise
*/
public function checkForUpdate(&$description) {
$updateNeeded = FALSE;
$notMigratedRowsCount = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows(
'uid',
'tt_content',
$this->addWhere
);
// Fetch records where the field contains file links
if ($notMigratedRowsCount > 0) {
$description = 'There are file links in RTE fields referencing files without using the file abstraction layer FAL.';
$updateNeeded = TRUE;
}
return $updateNeeded;
}
/**
* Performs the update.
*
* @param array &$dbQueries: queries done in this update
* @param mixed &$customMessages: custom messages
* @return boolean TRUE on success, FALSE on error
*/
public function performUpdate(array &$dbQueries, &$customMessages) {
$this->init();
if(!$this->storage) {
$customMessages = 'No file resource storage found';
return FALSE;
}
$records = $this->getRecordsFromTable('tt_content');
foreach($records as $singleRecord) {
$this->migrateRecord($singleRecord);
}
if(count($this->fileNotFoundErrors) > 0) {
$customMessages .= '<strong>' . count($this->fileNotFoundErrors). ' missing files:</strong><br />';
$customMessages .= implode('<br />', $this->fileNotFoundErrors);
if($this->convertedLinkCounter == 0) {
// no links converted only missing files: UPDATE was not successful
return FALSE;
}
}
if($this->convertedLinkCounter > 0) {
$customMessages = $this->convertedLinkCounter . ' links converted.<br />' . $customMessages;
} else {
$customMessages .= 'No file links found';
}
return TRUE;
}
/**
* Processes each record and updates the database
*
* @param array $record
* @return void
*/
protected function migrateRecord(array $record) {
$this->currentRecord = $record;
$convertedBodyText = $this->convertFileLink($record['bodytext']);
$GLOBALS['TYPO3_DB']->exec_UPDATEquery(
'tt_content',
'uid = ' . $record['uid'],
array('bodytext' => $convertedBodyText)
);
}
/**
* The actual transformation of the links
* pretty similar to TS_links_rte in RteHtmlParser
*
* @param $value
* @return string
*/
protected function convertFileLink($value) {
$blockSplit = $this->rteHtmlParser->splitIntoBlock('link', $value, 1);
foreach ($blockSplit as $k => $v) {
// Block
if ($k % 2) {
$tagCode = \TYPO3\CMS\Core\Utility\GeneralUtility::unQuoteFilenames(trim(substr($this->rteHtmlParser->getFirstTag($v), 0, -1)), TRUE);
$link_param = $tagCode[1];
if(intval(strpos($link_param, '/')) && strpos($link_param, 'http') === FALSE){
$fileObject = NULL;
if(@file_exists(PATH_site . '/' . $link_param)) {
try {
if(strpos($link_param, $this->fileAdminDir) !== FALSE) {
$fileObject = $this->storage->getFile('/' . str_replace($this->fileAdminDir,'',$link_param));
}
} catch (\TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException $notFoundException) {
$this->fileNotFoundErrors[] = $link_param . ' not indexed (referenced in content element ' . $this->currentRecord['uid'] . ' on page ' . $this->currentRecord['pid'] . ')';
}
if ($fileObject instanceof \TYPO3\CMS\Core\Resource\FileInterface) {
// It's a file
$fileLink = 'file:' . $fileObject->getUid();
$tagCode[1] = $fileLink;
$bTag = implode(' ', $tagCode) . '>';
$eTag = '</link>';
$blockSplit[$k] = $bTag . $this->convertFileLink($this->rteHtmlParser->removeFirstAndLastTag($blockSplit[$k])) . $eTag;
$this->convertedLinkCounter++;
}
} else {
// Nothing to be done if file not found
$this->fileNotFoundErrors[] = $link_param . ' not found (referenced in content element ' . $this->currentRecord['uid'] . ' on page ' . $this->currentRecord['pid'] . ')';
}
}
}
}
$convertedText = implode('', $blockSplit);
return $convertedText;
}
/**
* Retrieve every record which needs to be processe
*
* @return array
*/
protected function getRecordsFromTable() {
$records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,pid,bodytext', 'tt_content', $this->addWhere);
return $records;
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment